Documentation
¶
Overview ¶
Package pack provides scaffolding logic for rule packs and code packs. It handles template rendering, pack number resolution, and directory creation for the backstop pack new command.
Index ¶
- Variables
- func ExpectedLayout(m *Manifest, base engine.Registry) []string
- func NamespacedRuleID(packName, ruleID string) string
- func ValidateLanguage(language string) error
- func ValidatePackName(name string) error
- func ValidateRuleID(id string) error
- func ValidateSlug(slug string) error
- type Claim
- type Classification
- type Content
- type Coordinate
- type EngineSpec
- type FixtureEntry
- type Fixtures
- type Manifest
- type PairsWith
- type Rule
- type Ruleset
- type SDK
- type Scaffold
- type ScaffoldOptions
- type ScaffoldResult
- type ToolConfigEntry
- type ValidationError
Constants ¶
This section is empty.
Variables ¶
var ValidPackTypes = map[string]bool{ "engine": true, "mechanism": true, "toolchain": true, }
ValidPackTypes is the registry of valid pack types. ISSUE-032 (Defect A + ISSUE-030 fold): the retired native-standards world's "rule"/"code" types — which emitted a `.standard.md` / `.recipe.md` compiled by the DELETED standards compiler — are gone. The live pack shapes are engine-model packs (SPEC-031/SPEC-035): an `engine` pack (a self-contained sandbox-validator engine), a `mechanism` pack (wraps a native tool as an engine), and a `toolchain` pack (a language's native build/test/lint passes). All three scaffold to a VALID enforcement pack.yml with a declared engines: block — the packs-only substrate, no compiler in between.
Functions ¶
func ExpectedLayout ¶
ExpectedLayout returns the expected pack layout. The base engine registry is injected (ISSUE-027) so the rules/ vs validators/ derivation resolves a rule's binding through the base ∪ pack-declared union without a baked table.
func NamespacedRuleID ¶
NamespacedRuleID prefixes a rule ID with the pack name.
func ValidateLanguage ¶
ValidateLanguage checks that the language string matches ^[a-z]+$.
func ValidatePackName ¶
ValidatePackName reports whether name is a usable pack identity: exactly one slash, both parts non-empty, and every character within namePartPattern.
It is EXPORTED so pkg/pack/distribution can decide a cloned manifest's name with the same authority the manifest model itself uses (SPEC-056 REQ-003 / CLM-037). REQ-003 makes the manifest name the install path, the backstop.yml key, the lock key, and the engine asset root, so distribution must reject an unusable name BEFORE it writes any consumer state — and doing that with a second copy of this rule is the failure the requirement names outright. Two bodies that agree today drift tomorrow, and the drift surfaces as a pack one package accepts and the other rejects.
ONLY THE NAME RULE IS EXPORTED. validateSemver, semverPattern and namePartPattern stay unexported deliberately: semverPattern accepts prerelease and build-metadata suffixes, so a manifest declaring 1.0.0-rc1 is a VALID manifest that is nonetheless not installable by tag, because no strict release tag can equal it. Identity's version strictness must be NARROWER than the manifest model's, and exporting the model's semver rule would invite exactly the reuse that reintroduces that acceptance.
func ValidateRuleID ¶
ValidateRuleID validates lowercase kebab-case rule IDs.
func ValidateSlug ¶
ValidateSlug checks that the slug conforms to ^[a-z][a-z0-9]*(-[a-z0-9]+)*$ with a minimum length of 2 and maximum length of 64 characters.
Types ¶
type Claim ¶
type Claim struct {
ID string `yaml:"id"`
Text string `yaml:"text"`
Fixtures Fixtures `yaml:"fixtures"`
}
Claim defines a rule claim and fixture mappings.
type Classification ¶
type Classification struct {
Source []string `yaml:"source"`
Test []string `yaml:"test"`
// DependencyDirs are the bare directory NAMES — not globs, not paths — that
// the declaring pack's ecosystem uses for vendored or installed dependency
// trees (Go's `vendor`, npm's `node_modules`). Core excludes them from
// artifact-corpus walks ONLY because a pack declares them here; the binary
// bakes no ecosystem noun of its own (ISSUE-122, CLM-002).
//
// It lives on Classification rather than on an EngineBinding because it is a
// WHOLE-PACK, whole-walk property with no engine in hand: the corpus walks
// that consume it never hold an engine, and the fact being stated ("this
// directory is a dependency tree, not authored content") is the same kind of
// path-classification statement, by the same declarer, merged the same way as
// Source/Test. Absent key => nil, contributing nothing to the merged union.
//
// Core deliberately does NOT validate these names. It has no opinion about
// what an ecosystem calls its dependency tree, and inventing one would
// re-bake the knowledge as a validator.
DependencyDirs []string `yaml:"dependency_dirs"`
}
Classification is the pack-declared file-classification DATA (SPEC-043 REQ-001/CLM-001): two OPTIONAL glob lists a toolchain pack declares under the top-level `classification:` block. Source globs are patterns whose matches are SOURCE files coverage is expected for; Test globs are patterns whose matches are TEST/non-source files — a stack folds its fixture/testdata convention into Test (e.g. `**/testdata/**`) rather than a separate baked dimension. Absent block => zero value, no error (CLM-002). The binary bakes NO language-specific source/test convention; every stack supplies its own globs (DD-1).
type Content ¶
type Content struct {
Ruleset Ruleset `yaml:"ruleset"`
Scaffolds []Scaffold `yaml:"scaffolds"`
SDK *SDK `yaml:"sdk"`
}
Content contains rulesets, scaffolds, and SDK metadata.
type Coordinate ¶
Coordinate identifies a versioned pack item reference.
func ParseCoordinate ¶
func ParseCoordinate(ref string) (*Coordinate, error)
ParseCoordinate parses a versioned coordinate reference.
type EngineSpec ¶
type EngineSpec struct {
Command string `yaml:"command"`
InputMode string `yaml:"input_mode"`
InputFlag string `yaml:"input_flag"`
Convert string `yaml:"convert"`
// Producer is the optional pack-relative un-sandboxed producer script (symmetric
// with Convert) the dispatch runs to produce the engine's payload instead of the
// plain Command (ISSUE-045 option (ii)). Declared as pack DATA and converted to
// engine.EngineBinding.Producer at load; a missing key leaves it empty (the plain
// Command produces the payload). Wired through parseEngineSpec so a pack.yml
// producer: key is not silently dropped by the non-strict YAML decode.
Producer string `yaml:"producer"`
StdoutArtifact string `yaml:"stdout_artifact"`
ScopeKind string `yaml:"scope_kind"`
Category string `yaml:"category"`
GateType string `yaml:"gate_type"`
StrictSarif bool `yaml:"strict_sarif"`
PackageScoped bool `yaml:"package_scoped"`
ProjectTarget string `yaml:"project_target"`
// CrashGuard marks a findings engine whose non-zero exit with no parseable
// findings is a CRASH, not a finding-free green (the go build/test passes set
// it). It is DATA the go-toolchain pack declares so the toolchain's crash
// semantics live in the pack, not a baked binding (ISSUE-027).
CrashGuard bool `yaml:"crash_guard"`
// ExemptFromScopeFilter marks an engine whose violations bypass diff-scope
// filtering (the go-build declared build-exemption, SPEC-041 CLM-011). Declared
// as pack DATA so the exemption travels with the pack, not a baked binding.
ExemptFromScopeFilter bool `yaml:"exempt_from_scope_filter"`
Provision *engine.Provision `yaml:"provision"`
FieldContract *engine.FieldContract `yaml:"field_contract"`
// Binding is the engine.EngineBinding the spec converts to at load. It is
// populated by parseEngineSpec during ParseManifest, not parsed directly from
// yaml, so the string-enum spellings resolve through the fail-loud parsers.
Binding engine.EngineBinding `yaml:"-"`
}
EngineSpec is one entry in a pack manifest's top-level `engines:` block: the yaml-tagged surface a pack declares an execution engine with (SPEC-035 REQ-001/CLM-001). The string-valued scope_kind / category / input_mode / gate_type spellings are parsed into the engine package's enum types at load (parseEngineSpec); the resolved engine.EngineBinding is stored on Binding so every consumer reads ONE converted binding, never the raw spec.
type FixtureEntry ¶
FixtureEntry is either a plain string path or object with metadata.
func (*FixtureEntry) UnmarshalYAML ¶
func (f *FixtureEntry) UnmarshalYAML(unmarshal func(interface{}) error) error
UnmarshalYAML handles fixture polymorphism.
type Fixtures ¶
type Fixtures struct {
Positive []FixtureEntry `yaml:"positive"`
Negative []FixtureEntry `yaml:"negative"`
}
Fixtures maps claim fixtures.
type Manifest ¶
type Manifest struct {
Name string `yaml:"name"`
NormalizedName string `yaml:"-"`
Version string `yaml:"version"`
Language string `yaml:"language"`
Archetype string `yaml:"archetype"`
Description string `yaml:"description"`
Content Content `yaml:"content"`
ToolConfig []ToolConfigEntry `yaml:"tool_config"`
// Engines holds the pack-declared engine bindings parsed from the top-level
// `engines:` block (SPEC-035 REQ-001/CLM-001). Each EngineSpec carries the
// yaml-tagged binding fields and is converted to an engine.EngineBinding at
// load (EngineSpec.Binding). resolveEngineRegistry merges these over the
// fallback registry so a rule's declared engine resolves to the pack-declared
// binding when present.
Engines map[string]EngineSpec `yaml:"engines"`
// Classification holds the pack-declared file-classification globs parsed from
// the OPTIONAL top-level `classification:` block (SPEC-043 REQ-001/CLM-001).
// A toolchain pack declares which files are SOURCE (coverage is expected for
// them) and which are TEST/non-source via two glob lists; the language-neutral
// coverage consumer reads the MERGED UNION of these across all declared packs
// instead of a baked `.go` literal. The block is OPTIONAL: a manifest with no
// `classification:` yields the zero value with no parse error (CLM-002). The
// binary holds NO baked source/test convention — every stack supplies its own
// globs (DD-1, the thin-executor first principle).
Classification Classification `yaml:"classification"`
// TestNamePatterns holds the pack-declared test-name/indicator regexes parsed
// from the OPTIONAL top-level `test_name_patterns:` block (SPEC-045 REQ-002/
// CLM-010..CLM-018). Each pattern's capture group 1 is the test name; the
// gate merges the UNION across declared toolchain packs and compiles them into
// a gate.TestNameMatcher, replacing the DELETED baked `funcPattern`. The
// go-toolchain reference declares the `func Test...` regex AS DATA; a bun pack
// declares the `test(...)`/`describe(...)`/`it(...)` regexes. Optional;
// zero-value (nil) when the block is absent. The list is opaque DATA at parse
// time — no compilation here (the gate compiles it, loud-on-invalid). DISJOINT
// from SPEC-043's Classification field on this same struct (DD-1, the
// thin-executor first principle: no baked language/test convention in the
// binary).
TestNamePatterns []string `yaml:"test_name_patterns"`
// Recipes holds the OPTIONAL top-level `recipes:` index parsed from pack.yml
// (SPEC-054 REQ-008/CLM-032..035): a stable recipe id mapped to the
// pack-relative directory holding that recipe's recipe.yml and payload. It is
// a DISTINCT top-level key from Content.Scaffolds (a rule's paired test
// scaffold) and unrelated to pack authoring; declaring both is valid and the
// two never populate each other (CLM-033). Zero-value (nil) when absent.
// validateRecipesIndex checks each entry structurally at ParseManifestFile,
// where the pack root is known.
Recipes map[string]string `yaml:"recipes"`
}
Manifest is the top-level pack manifest.
func ParseManifest ¶
ParseManifest parses and validates pack.yml bytes.
func ParseManifestFile ¶
ParseManifestFile reads and parses a manifest file. It is the only production entry point that knows where the pack lives, so the `recipes:` index — whose entries are pack-relative directories — is validated here against the pack root. ParseManifest([]byte) has no root and therefore parses the index without checking it.
type PairsWith ¶
type PairsWith struct {
Rules []string `yaml:"rules"`
Scaffolds []string `yaml:"scaffolds"`
SDK string `yaml:"sdk"`
}
PairsWith groups relationships to other elements.
type Rule ¶
type Rule struct {
ID string `yaml:"id"`
NamespacedID string `yaml:"-"`
Engine string `yaml:"engine"`
Standard string `yaml:"standard"`
RulePath string `yaml:"rule_path"`
// Pattern is the inline rule pattern a pattern-arg engine passes as a command
// argument instead of resolving a rule file on disk (SPEC-035 REQ-004). Empty
// for non-pattern-arg engines; an empty Pattern under a pattern-arg engine is
// a blocking broken-pack config error at gather time (CLM-017).
Pattern string `yaml:"pattern"`
RiskClass string `yaml:"risk_class"`
Claims []Claim `yaml:"claims"`
Category string `yaml:"category"`
Justification string `yaml:"justification"`
Validator string `yaml:"validator"`
InputScope string `yaml:"input_scope"`
PairsWith PairsWith `yaml:"pairs_with"`
// NonWaivable marks a rule as self-declared un-waivable (SPEC-049 REQ-006): a
// @waiver token targeting it is a gate ERROR, not a suppression. This is the
// pack-manifest DECLARATION the production waiver Policy is EXTRACTED from
// (CLM-069, the "declared, not core-hardcoded" mechanism) — the shipped
// backstop/self pack marks its rules non_waivable here. Optional; zero value
// (false) leaves the rule waivable.
NonWaivable bool `yaml:"non_waivable"`
}
Rule defines a single rule entry. The execution engine is declared via the first-class Engine field (SPEC-031 REQ-001); the retired Layer field and its yaml key are gone (REQ-002). A rule whose engine is empty is a blocking ConfigError at the migrated reader — there is no layer:2 -> engine:semgrep aliasing (REQ-002/REQ-015).
type SDK ¶
type SDK struct {
Module string `yaml:"module"`
Version string `yaml:"version"`
Provides []string `yaml:"provides"`
}
SDK describes an SDK dependency.
type Scaffold ¶
type Scaffold struct {
ID string `yaml:"id"`
Version string `yaml:"version"`
Tier string `yaml:"tier"`
Path string `yaml:"path"`
TestCommand string `yaml:"test_command"`
Description string `yaml:"description"`
UseWhen []string `yaml:"use_when"`
Assumes []string `yaml:"assumes"`
PairsWith PairsWith `yaml:"pairs_with"`
SampleConfig map[string]any `yaml:"sample_config"`
}
Scaffold describes a scaffolded asset.
type ScaffoldOptions ¶
ScaffoldOptions holds options for pack scaffolding.
type ScaffoldResult ¶
type ScaffoldResult struct {
Paths []string `json:"paths"`
PackID string `json:"pack_id"`
Type string `json:"type"`
Language string `json:"language"`
Slug string `json:"slug"`
SchemaVersion string `json:"schema_version"`
}
ScaffoldResult holds the result of scaffolding.
func ScaffoldPack ¶
func ScaffoldPack(opts ScaffoldOptions) (*ScaffoldResult, error)
ScaffoldPack creates the pack directory and template files for the given pack type. Every valid type produces a self-contained enforcement pack whose declared engines: block + sample rule pass `pack check`, `pack test`, and the gate (Defect A / CLM-001).
func (*ScaffoldResult) HumanString ¶
func (r *ScaffoldResult) HumanString() string
HumanString formats the result for human display.
type ToolConfigEntry ¶
type ToolConfigEntry struct {
ID string `yaml:"id"`
Tool string `yaml:"tool"`
File string `yaml:"file"`
Settings map[string]any `yaml:"settings"`
RiskClass string `yaml:"risk_class"`
Claims []Claim `yaml:"claims"`
RequiredBy string `yaml:"required_by"`
}
ToolConfigEntry describes a tool config item.
type ValidationError ¶
ValidationError describes a manifest validation violation.
func ValidateManifest ¶
func ValidateManifest(m *Manifest, base engine.Registry) []ValidationError
ValidateManifest validates manifest constraints and returns all violations. The base engine registry (the four generic built-ins loaded from the embedded base-engines pack) is INJECTED as a parameter (ISSUE-027, option a): the engine field-contract + layout resolution seed from it instead of a baked engine.DefaultRegistry(), so pkg/pack holds zero baked engine knowledge and never imports the embed loader (which would be an import cycle). The CLI passes baseengines.Registry(); a pack-declared engine still overrides a same-named base binding.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package distribution implements the pack distribution lifecycle: six commands (pack add, pack remove, pack install, pack update, pack upgrade, pack list) plus the backstop.lock format, SHA-256 content hashing, gate-time lock verification, tool_config provenance tracking, and .backstop/packs/ lifecycle management.
|
Package distribution implements the pack distribution lifecycle: six commands (pack add, pack remove, pack install, pack update, pack upgrade, pack list) plus the backstop.lock format, SHA-256 content hashing, gate-time lock verification, tool_config provenance tracking, and .backstop/packs/ lifecycle management. |
|
Package engine holds the shared EngineBinding table that the gate uses to dispatch pack-rule enforcement onto a declared execution engine.
|
Package engine holds the shared EngineBinding table that the gate uses to dispatch pack-rule enforcement onto a declared execution engine. |