Documentation
¶
Index ¶
- Constants
- func CheckVersionConstraint(constraint, resolved string) (bool, error)
- func CleanBuildCache(cacheDir string) error
- func Compose(sol *solution.Solution, bundleRoot string, opts ...ComposeOption) (*solution.Solution, error)
- func ComputeBuildFingerprint(solutionContent []byte, bundleRoot string, discoveredFiles []FileEntry, ...) (string, error)
- func CountBuildCacheEntries(cacheDir string) int
- func ExtractDeduplicatedBundle(manifest *BundleManifest, destDir string, ...) error
- func MergePluginDefaults(sol *solution.Solution)
- func ValidatePlugins(sol *solution.Solution) error
- func VendorFileNameFromRef(ref string, info catalog.ArtifactInfo) string
- func WriteBuildCache(cacheDir, fingerprint string, entry *BuildCacheEntry) error
- func WriteLockFile(path string, lf *LockFile) error
- type BuildCacheEntry
- type BundleFileEntry
- type BundleManifest
- type BundlePluginEntry
- type CatalogFetcher
- type CatalogRefEntry
- type ComposeOption
- type DedupeFileBlob
- type DedupeOption
- type DedupeResult
- type DiscoverOption
- type DiscoveryResult
- type DiscoverySource
- type DynamicPathWarning
- type FileEntry
- type IgnoreChecker
- type LockDependency
- type LockFile
- type LockPlugin
- type PluginResolver
- type ScafctlIgnore
- type TarOption
- type VendorOptions
- type VendorPluginsOptions
- type VendorPluginsResult
- type VendorResult
Constants ¶
const ( // BundleManifestVersion1 is the original tar-based bundle format. BundleManifestVersion1 = 1 // BundleManifestVersion2 is the content-addressable deduplicated format. BundleManifestVersion2 = 2 // DefaultDedupeThreshold is the minimum file size for individual layer extraction. // Files smaller than this are grouped into a single tar layer. DefaultDedupeThreshold int64 = 4 * 1024 // 4 KB )
const ( // LockFileVersion is the current lock file format version. LockFileVersion = 1 // DefaultLockFileName is the default lock file name. DefaultLockFileName = "solution.lock" )
const ( // BundleManifestPath is the path within the tar archive for the bundle manifest. BundleManifestPath = ".scafctl/bundle-manifest.json" // DefaultMaxBundleSize is the default maximum total size of bundled files (50 MB). DefaultMaxBundleSize int64 = 50 * 1024 * 1024 )
const (
// VendorDirName is the directory name within the bundle for vendored artifacts.
VendorDirName = ".scafctl/vendor"
)
Variables ¶
This section is empty.
Functions ¶
func CheckVersionConstraint ¶
CheckVersionConstraint checks if a resolved version satisfies a version constraint.
func CleanBuildCache ¶ added in v0.3.0
CleanBuildCache removes all entries from the build cache directory.
func Compose ¶
func Compose(sol *solution.Solution, bundleRoot string, opts ...ComposeOption) (*solution.Solution, error)
Compose loads and merges all composed files referenced by the solution. The composed files are expected to contain partial YAML with spec.resolvers, spec.workflow.actions, and/or bundle.include sections.
Returns a new Solution with all parts merged. The original is not modified. bundleRoot is the directory containing the root solution YAML — composed file paths are resolved relative to it.
Merge rules:
- Resolvers: merged by name. Duplicate resolver names across files are rejected.
- Actions: merged by name. Duplicate action names across files are rejected.
- Finally actions: merged by name. Same duplicate rules apply.
- Tests: merged by name. Duplicate test names across files are rejected.
- TestConfig: skipBuiltins (true-wins for bool, union for lists), env (last wins), setup/cleanup (appended in compose-file order).
- bundle.include: unioned (deduplicated).
- Circular compose references are detected and rejected.
func ComputeBuildFingerprint ¶ added in v0.3.0
func ComputeBuildFingerprint(solutionContent []byte, bundleRoot string, discoveredFiles []FileEntry, plugins []BundlePluginEntry, lockDigest string) (string, error)
ComputeBuildFingerprint computes a SHA-256 fingerprint from the solution content, discovered file contents, plugin versions, and lock file digest.
The fingerprint changes when any input to the build changes, enabling incremental builds by skipping the entire pipeline when inputs are unchanged.
func CountBuildCacheEntries ¶ added in v0.3.0
CountBuildCacheEntries returns the number of cache entries in the directory.
func ExtractDeduplicatedBundle ¶
func ExtractDeduplicatedBundle(manifest *BundleManifest, destDir string, layerFetcher func(layer int) ([]byte, error)) error
ExtractDeduplicatedBundle extracts a version 2 bundle from individual OCI layers. layerFetcher returns the raw bytes of a layer by its 0-based index.
func MergePluginDefaults ¶
MergePluginDefaults shallow-merges plugin default inputs beneath inline provider inputs in the solution's resolvers and actions. Inline inputs always win. This should be called before DAG construction so that the DAG sees the merged result.
func ValidatePlugins ¶
ValidatePlugins validates all plugin declarations in a solution's bundle. Returns an error if any plugin has invalid name, kind, or version constraint.
func VendorFileNameFromRef ¶
func VendorFileNameFromRef(ref string, info catalog.ArtifactInfo) string
VendorFileNameFromRef generates the file name for a vendored artifact (exported).
func WriteBuildCache ¶ added in v0.3.0
func WriteBuildCache(cacheDir, fingerprint string, entry *BuildCacheEntry) error
WriteBuildCache writes a build cache entry for the given fingerprint.
func WriteLockFile ¶
WriteLockFile serializes and writes the lock file to the given path.
Types ¶
type BuildCacheEntry ¶ added in v0.3.0
type BuildCacheEntry struct {
// Fingerprint is the SHA-256 hash of all build inputs.
Fingerprint string `json:"fingerprint"`
// ArtifactName is the name of the built artifact.
ArtifactName string `json:"artifactName"`
// ArtifactVersion is the version of the built artifact.
ArtifactVersion string `json:"artifactVersion"`
// ArtifactDigest is the OCI digest of the stored artifact.
ArtifactDigest string `json:"artifactDigest"`
// CreatedAt is when this cache entry was written.
CreatedAt time.Time `json:"createdAt"`
// InputFiles records the number of input files that contributed to the fingerprint.
InputFiles int `json:"inputFiles"`
}
BuildCacheEntry records a successful build result for cache hit detection.
func CheckBuildCache ¶ added in v0.3.0
func CheckBuildCache(cacheDir, fingerprint string) (*BuildCacheEntry, bool)
CheckBuildCache checks if a build cache entry exists for the given fingerprint. Returns the cache entry and true if found, nil and false if not.
type BundleFileEntry ¶
type BundleFileEntry struct {
// Path is the file's path relative to the bundle root.
Path string `json:"path"`
// Size is the file size in bytes.
Size int64 `json:"size"`
// Digest is the SHA-256 content digest.
Digest string `json:"digest"`
// Layer is the OCI layer index for this file (version 2 only).
// In version 1 manifests, this is omitted (all files are in the tar layer).
Layer int `json:"layer,omitempty"`
}
BundleFileEntry describes a single file in the bundle.
type BundleManifest ¶
type BundleManifest struct {
// Version is the manifest format version.
Version int `json:"version"`
// Root is the bundle root directory (always ".").
Root string `json:"root"`
// Files lists all bundled files with their paths, sizes, and content digests.
Files []BundleFileEntry `json:"files"`
// Plugins lists plugin dependencies (informational, recorded from bundle.plugins).
Plugins []BundlePluginEntry `json:"plugins,omitempty"`
}
BundleManifest describes the contents of a bundle tar archive.
func CreateBundleTar ¶
func CreateBundleTar(bundleRoot string, files []FileEntry, plugins []BundlePluginEntry, opts ...TarOption) ([]byte, *BundleManifest, error)
CreateBundleTar creates a tar archive containing the discovered files and a bundle manifest. Returns the tar bytes and the manifest.
func ExtractBundleTar ¶
func ExtractBundleTar(tarData []byte, destDir string) (*BundleManifest, error)
ExtractBundleTar extracts a bundle tar archive to a destination directory. Returns the bundle manifest.
func ExtractBundleTarFromReader ¶
func ExtractBundleTarFromReader(r io.Reader, destDir string) (*BundleManifest, error)
ExtractBundleTarFromReader extracts a tar archive from a reader to a destination directory.
type BundlePluginEntry ¶
type BundlePluginEntry struct {
// Name is the plugin's catalog reference.
Name string `json:"name"`
// Kind is the plugin type (provider, auth-handler).
Kind string `json:"kind"`
// Version is the semver constraint.
Version string `json:"version"`
}
BundlePluginEntry describes a plugin dependency in the bundle manifest.
func PluginsToBundleEntries ¶
func PluginsToBundleEntries(plugins []solution.PluginDependency) []BundlePluginEntry
PluginsToBundleEntries converts solution plugin dependencies to bundle manifest entries.
type CatalogFetcher ¶
type CatalogFetcher interface {
// FetchSolution retrieves a solution by name[@version] and returns
// the content bytes, the resolved reference info, and any error.
FetchSolution(ctx context.Context, nameWithVersion string) (content []byte, info catalog.ArtifactInfo, err error)
// ListSolutions returns all available versions for a named solution artifact.
// Used for resolving semver constraints to the best matching version.
ListSolutions(ctx context.Context, name string) ([]catalog.ArtifactInfo, error)
}
CatalogFetcher fetches solution content from a catalog by reference.
type CatalogRefEntry ¶
type CatalogRefEntry struct {
// Ref is the original catalog reference (e.g., "deploy-to-k8s@2.0.0").
Ref string
// VendorPath is the path within the bundle where the vendored artifact is stored.
VendorPath string
}
CatalogRefEntry represents a catalog dependency to vendor.
type ComposeOption ¶
type ComposeOption func(*composeConfig)
ComposeOption configures Compose behavior.
func WithReadFileFunc ¶
func WithReadFileFunc(fn func(string) ([]byte, error)) ComposeOption
WithReadFileFunc overrides the function used to read composed files. Useful for testing without touching the filesystem.
type DedupeFileBlob ¶
type DedupeFileBlob struct {
// RelPath is the file path relative to the bundle root.
RelPath string
// Content is the file's raw bytes.
Content []byte
// Digest is the SHA-256 content digest.
Digest string
// Size is the file size in bytes.
Size int64
// Layer is the 0-based layer index in the OCI manifest (set after partitioning).
Layer int
}
DedupeFileBlob represents a single file prepared for content-addressable storage.
type DedupeOption ¶
type DedupeOption func(*dedupeConfig)
DedupeOption configures deduplication behavior.
func WithDedupeMaxSize ¶
func WithDedupeMaxSize(size int64) DedupeOption
WithDedupeMaxSize sets the maximum total size of all bundled files.
func WithDedupeReadFileFunc ¶
func WithDedupeReadFileFunc(fn func(string) ([]byte, error)) DedupeOption
WithDedupeReadFileFunc overrides the file reading function for testing.
func WithDedupeThreshold ¶
func WithDedupeThreshold(size int64) DedupeOption
WithDedupeThreshold sets the minimum file size for individual blob layers. Files smaller than this threshold are grouped into a combined tar layer.
type DedupeResult ¶
type DedupeResult struct {
// Manifest is the bundle manifest (version 2).
Manifest *BundleManifest
// ManifestJSON is the serialized manifest.
ManifestJSON []byte
// LargeBlobs are individual file blobs stored as separate OCI layers.
LargeBlobs []DedupeFileBlob
// SmallBlobsTar is a tar archive of files below the dedup threshold.
// May be nil if there are no small files.
SmallBlobsTar []byte
// TotalSize is the sum of all file sizes.
TotalSize int64
}
DedupeResult contains the output of content-addressable deduplication.
func CreateDeduplicatedBundle ¶
func CreateDeduplicatedBundle(bundleRoot string, files []FileEntry, plugins []BundlePluginEntry, opts ...DedupeOption) (*DedupeResult, error)
CreateDeduplicatedBundle prepares files for content-addressable OCI storage. Large files (>= threshold) become individual layers; small files are tarred together. Returns a DedupeResult containing the manifest and all blobs to push.
type DiscoverOption ¶
type DiscoverOption func(*discoverConfig)
DiscoverOption configures DiscoverFiles behavior.
func WithDiscoverReadFileFunc ¶
func WithDiscoverReadFileFunc(fn func(string) ([]byte, error)) DiscoverOption
WithDiscoverReadFileFunc overrides os.ReadFile for testing.
func WithIgnoreChecker ¶
func WithIgnoreChecker(ic IgnoreChecker) DiscoverOption
WithIgnoreChecker sets a custom ignore checker for file exclusion.
func WithStatFunc ¶
func WithStatFunc(fn func(string) (os.FileInfo, error)) DiscoverOption
WithStatFunc overrides os.Stat for testing.
func WithWalkDirFunc ¶
func WithWalkDirFunc(fn func(string, filepath.WalkFunc) error) DiscoverOption
WithWalkDirFunc overrides filepath.Walk for testing.
type DiscoveryResult ¶
type DiscoveryResult struct {
// LocalFiles are local file paths relative to the bundle root.
LocalFiles []FileEntry
// CatalogRefs are catalog references to vendor.
CatalogRefs []CatalogRefEntry
}
DiscoveryResult contains all files and dependencies discovered during analysis.
func DiscoverFiles ¶
func DiscoverFiles(sol *solution.Solution, bundleRoot string, opts ...DiscoverOption) (*DiscoveryResult, error)
DiscoverFiles performs static analysis on a parsed (and composed) solution to find local file references and catalog references, then combines them with explicit bundle includes.
Returns deduplicated lists of local files and catalog references.
type DiscoverySource ¶
type DiscoverySource int
DiscoverySource indicates how a file was discovered for bundling.
const ( // StaticAnalysis means the file was discovered by walking provider inputs. StaticAnalysis DiscoverySource = iota // ExplicitInclude means the file was declared in bundle.include. ExplicitInclude // TestInclude means the file was referenced in spec.tests[*].files. TestInclude )
func (DiscoverySource) String ¶
func (d DiscoverySource) String() string
String returns a human-readable label for the discovery source.
type DynamicPathWarning ¶
type DynamicPathWarning struct {
// Location describes where in the solution the dynamic path was found
// (e.g., "resolver 'templatePath'").
Location string
// Kind is the type of dynamic reference ("expr", "tmpl", "rslvr").
Kind string
// Expression is the dynamic expression value.
Expression string
}
DynamicPathWarning describes a provider input that uses a dynamic path (CEL expression, Go template, or resolver binding) which cannot be statically analyzed for file bundling.
func DetectDynamicPaths ¶
func DetectDynamicPaths(sol *solution.Solution) []DynamicPathWarning
DetectDynamicPaths scans a solution for provider inputs that use dynamic paths (CEL, Go templates, resolver bindings) in file-related fields. These paths cannot be statically analyzed and should be covered by bundle.include patterns.
type FileEntry ¶
type FileEntry struct {
// RelPath is the path relative to the bundle root.
RelPath string
// Source indicates how the file was discovered.
Source DiscoverySource
}
FileEntry represents a local file to be bundled.
type IgnoreChecker ¶
type IgnoreChecker interface {
// IsIgnored returns true if the given relative path should be excluded.
IsIgnored(relPath string) bool
}
IgnoreChecker determines whether a file path should be excluded from bundling.
func LoadScafctlIgnore ¶
func LoadScafctlIgnore(bundleRoot string) (IgnoreChecker, error)
LoadScafctlIgnore reads a .scafctlignore file and returns an IgnoreChecker. If the file does not exist, a no-op checker is returned (nothing is ignored).
func LoadScafctlIgnoreFrom ¶
func LoadScafctlIgnoreFrom(path string) (IgnoreChecker, error)
LoadScafctlIgnoreFrom reads ignore patterns from a specific file path.
func ParseIgnorePatterns ¶
func ParseIgnorePatterns(patterns []string) IgnoreChecker
ParseIgnorePatterns creates an IgnoreChecker from a list of pattern strings. Useful for testing.
type LockDependency ¶
type LockDependency struct {
// Ref is the original catalog reference (e.g., "deploy-to-k8s@2.0.0" or "deploy-to-k8s@^1.5.0").
Ref string `json:"ref" yaml:"ref" doc:"Original catalog reference" maxLength:"255" example:"deploy-to-k8s@2.0.0"`
// ResolvedVersion is the exact semver version that was resolved and vendored.
// For exact refs like "deploy-to-k8s@2.0.0" this equals the version in Ref.
// For constraint refs like "deploy-to-k8s@^1.5.0" this is the resolved version (e.g., "1.5.2").
ResolvedVersion string `json:"resolvedVersion,omitempty" yaml:"resolvedVersion,omitempty" doc:"Exact resolved version" maxLength:"50" example:"1.5.2"`
// Constraint is the original version constraint, if any (e.g., "^1.5.0", ">=2.0.0").
// Empty for exact version references.
Constraint string `json:"constraint,omitempty" yaml:"constraint,omitempty" doc:"Original version constraint" maxLength:"100" example:"^1.5.0"`
// Digest is the SHA-256 content digest of the vendored file.
Digest string `json:"digest" yaml:"digest" doc:"SHA-256 content digest" maxLength:"128" example:"sha256:abc123..."`
// ResolvedFrom is the catalog name from which the dependency was fetched.
ResolvedFrom string `json:"resolvedFrom" yaml:"resolvedFrom" doc:"Source catalog name" maxLength:"255" example:"company-catalog"`
// VendoredAt is the path relative to the bundle root where the file is stored.
VendoredAt string `` /* 139-byte string literal not displayed */
}
LockDependency records metadata about a vendored catalog dependency.
type LockFile ¶
type LockFile struct {
// Version is the lock file format version.
Version int `json:"version" yaml:"version" doc:"Lock file format version" example:"1"`
// Dependencies lists vendored solution dependencies with their digests.
Dependencies []LockDependency `json:"dependencies,omitempty" yaml:"dependencies,omitempty" doc:"Vendored solution dependencies" maxItems:"1000"`
// Plugins lists vendored plugin dependencies with their digests.
Plugins []LockPlugin `json:"plugins,omitempty" yaml:"plugins,omitempty" doc:"Vendored plugin dependencies" maxItems:"100"`
}
LockFile represents the lock file that records vendored dependency state. It enables reproducible builds by replaying exact versions and digests.
func LoadLockFile ¶
LoadLockFile reads and parses a lock file from the given path. Returns nil without error if the file does not exist.
func (*LockFile) FindDependency ¶
func (lf *LockFile) FindDependency(ref string) *LockDependency
FindDependency returns the lock entry for the given ref, or nil if not found. It first tries an exact Ref match, then falls back to matching by name (the part before @) to support constraint-based refs where the constraint string may differ between runs.
func (*LockFile) FindDependencyByName ¶ added in v0.3.0
func (lf *LockFile) FindDependencyByName(name string) *LockDependency
FindDependencyByName returns the lock entry matching the artifact name, or nil.
func (*LockFile) FindPlugin ¶
func (lf *LockFile) FindPlugin(name, kind string) *LockPlugin
FindPlugin returns the lock entry for a plugin by name and kind, or nil if not found.
type LockPlugin ¶
type LockPlugin struct {
// Name is the plugin name.
Name string `json:"name" yaml:"name" doc:"Plugin name" maxLength:"100" example:"azure-provider"`
// Kind is the plugin kind (e.g., "provider", "auth-handler").
Kind string `json:"kind" yaml:"kind" doc:"Plugin kind" maxLength:"50" example:"provider"`
// Version is the resolved version string.
Version string `json:"version" yaml:"version" doc:"Resolved version" maxLength:"50" example:"1.2.3"`
// Digest is the SHA-256 content digest.
Digest string `json:"digest" yaml:"digest" doc:"SHA-256 content digest" maxLength:"128" example:"sha256:abc123..."`
// ResolvedFrom is the source registry or catalog.
ResolvedFrom string `json:"resolvedFrom" yaml:"resolvedFrom" doc:"Source registry or catalog" maxLength:"255" example:"plugins.example.com"`
}
LockPlugin records metadata about a vendored plugin dependency.
type PluginResolver ¶ added in v0.3.0
type PluginResolver interface {
// ResolvePlugin resolves a plugin by name and kind, returning its metadata.
// If version constraint is non-empty, the resolver should pick the best
// matching version. Returns the artifact info with the resolved version and digest.
ResolvePlugin(ctx context.Context, name string, kind catalog.ArtifactKind, versionConstraint string) (catalog.ArtifactInfo, error)
}
PluginResolver resolves plugin artifacts from the catalog.
type ScafctlIgnore ¶
type ScafctlIgnore struct {
// contains filtered or unexported fields
}
ScafctlIgnore implements IgnoreChecker using .scafctlignore rules. It supports a subset of .gitignore syntax:
- Blank lines and lines starting with # are ignored.
- Patterns are matched against relative paths using filepath.Match.
- A trailing / matches only directories (not supported yet — treated as prefix match).
- A leading / anchors to the bundle root.
- ** is supported via doublestar matching.
func (*ScafctlIgnore) IsIgnored ¶
func (si *ScafctlIgnore) IsIgnored(relPath string) bool
IsIgnored returns true if the relative path matches any ignore pattern.
type TarOption ¶
type TarOption func(*tarConfig)
TarOption configures tar creation behavior.
func WithMaxBundleSize ¶
WithMaxBundleSize sets the maximum total size for the bundle.
type VendorOptions ¶
type VendorOptions struct {
// BundleRoot is the root directory of the solution bundle.
BundleRoot string
// VendorDir is the directory to store vendored artifacts.
VendorDir string
// LockPath is the path to the lock file.
LockPath string
// CatalogFetcher fetches artifacts from catalogs by name[@version].
// If nil, vendoring will fail when catalog refs are discovered.
CatalogFetcher CatalogFetcher
}
VendorOptions configures the vendoring process.
type VendorPluginsOptions ¶ added in v0.3.0
type VendorPluginsOptions struct {
// PluginResolver resolves plugins from the catalog.
// If nil, plugin vendoring is skipped.
PluginResolver PluginResolver
}
VendorPluginsOptions configures the plugin vendoring process.
type VendorPluginsResult ¶ added in v0.3.0
type VendorPluginsResult struct {
// ResolvedPlugins contains the lock entries for resolved plugins.
ResolvedPlugins []LockPlugin
}
VendorPluginsResult describes the outcome of plugin vendoring.
func VendorPlugins ¶ added in v0.3.0
func VendorPlugins(ctx context.Context, plugins []solution.PluginDependency, existingLock *LockFile, opts VendorPluginsOptions) (*VendorPluginsResult, error)
VendorPlugins resolves plugin dependencies against the catalog and records them in the lock file for reproducible builds. Unlike solution vendoring, plugins are not downloaded during build — only their versions and digests are pinned. The runtime fetches plugin binaries as needed.
type VendorResult ¶
type VendorResult struct {
// VendoredFiles contains relative paths (from bundle root) to vendored files.
VendoredFiles []string
// Lock is the updated lock file content.
Lock *LockFile
}
VendorResult describes the outcome of a vendoring operation.
func VendorDependencies ¶
func VendorDependencies(ctx context.Context, sol *solution.Solution, refs []CatalogRefEntry, opts VendorOptions) (*VendorResult, error)
VendorDependencies fetches catalog dependencies, stores them locally, rewrites source references in the solution, and writes a lock file.