lockfile

package
v1.225.0 Latest Latest
Warning

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

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

Documentation

Overview

Package lockfile stores the immutable identities and installed-file inventory produced by Atmos vendoring.

intentionally throughout this file (map iteration + mutate + reassign, by-value receipt building); pointer indirection would fight the existing read-modify-write pattern LockFile's map requires (Go cannot take the address of a map value).

Index

Constants

View Source
const (
	// DefaultFileName is the default committed vendor lock file.
	DefaultFileName = "vendor.lock.yaml"
)

Variables

View Source
var (
	// Load/Save.
	ErrReadVendorLock               = errors.New("read vendor lock")
	ErrParseVendorLock              = errors.New("parse vendor lock")
	ErrUnsupportedVendorLockVersion = errors.New("unsupported vendor lock version")
	ErrMarshalVendorLock            = errors.New("marshal vendor lock")
	ErrCreateVendorLockDir          = errors.New("create vendor lock directory")
	ErrCreateTempVendorLock         = errors.New("create temporary vendor lock")
	ErrWriteTempVendorLock          = errors.New("write temporary vendor lock")
	ErrSetVendorLockPermissions     = errors.New("set vendor lock permissions")
	ErrCloseTempVendorLock          = errors.New("close temporary vendor lock")
	ErrReplaceVendorLock            = errors.New("replace vendor lock")

	// Inventory / Record.
	ErrInventoryWalk = errors.New("inventory vendor tree")

	// Target/path security-boundary checks.
	ErrNormalizeLockTarget         = errors.New("normalize lock target")
	ErrNormalizeArtifactTarget     = errors.New("normalize artifact target")
	ErrInvalidLockOwnedFilePath    = errors.New("invalid lock-owned file path")
	ErrInvalidVendorLockTarget     = errors.New("invalid vendor lock target")
	ErrAbsoluteVendorLockTarget    = errors.New("invalid absolute vendor lock target")
	ErrVendorLockTargetEscapesRoot = errors.New("vendor lock target escapes project root")
	ErrMakeTargetRelative          = errors.New("make target relative to project root")
	ErrGetProjectRoot              = errors.New("get project root")
	ErrResolveProjectRoot          = errors.New("resolve project root")

	// Replace/Clean file operations.
	ErrInspectLockOwnedFile       = errors.New("inspect lock-owned file")
	ErrStaleLockOwnedFileModified = errors.New("stale lock-owned file was modified")
	ErrRemoveLockOwnedFile        = errors.New("remove lock-owned file")
)

Sentinel errors for pkg/vendoring/lockfile. These are package-local rather than centralized in errors/errors.go: they're internal invariants of this package's own lock-file contract (corruption, security-boundary checks, I/O failures during Save/Replace/Clean), meaningful only to this package's own callers and tests, not a cross-package contract other packages match against. This mirrors the existing internal/exec/vendor*.go convention of package-local sentinels, applied here for the first time to this package.

Functions

func ArtifactID

func ArtifactID(config *schema.AtmosConfiguration, kind, target string, writers ...string) (string, error)

ArtifactID returns a stable key for the writer that owns a target. The declared source is deliberately not part of the key: a new declared ref for the same target replaces the old receipt and can safely prune its stale files.

Target is relativized against config's project base before hashing (the same projectRelativeTarget normalization Replace/IsMaterialized already apply to the stored Target field) so the same logical artifact hashes to the same ID regardless of the checkout's absolute path. Without this, a vendor.lock.yaml committed to git -- its entire purpose -- would never match on a different developer's or CI runner's checkout, since every installer computes this ID from an absolute path (see ResolveComponentPath's own doc comment on why that path is absolute).

func FilesDigest

func FilesDigest(files []File) string

FilesDigest returns the deterministic SHA-256 identity for an installation manifest. It is used only when a source has no stronger immutable identity.

func Path

func Path(config *schema.AtmosConfiguration) string

Path returns the absolute vendor lock path for the given Atmos configuration.

func Record

func Record(ctx context.Context, atmosConfig *schema.AtmosConfiguration, target RecordTarget, opts RecordOptions) error

Record inventories target.TempDir (honoring opts), resolves target.DeclaredSource's immutable identity via downloader.ResolveArtifact (falling back to a files digest when the resolver has none), and replaces the lock artifact identified by (target.Kind, target.Path, target.Name[, opts.MixinFilename]). This is the single writer of vendor.lock.yaml artifacts — every install path (vendor.yaml sources, component.yaml sources, and mixins) calls this instead of hand rolling the inventory->resolve->Replace sequence itself.

func Replace

func Replace(config *schema.AtmosConfiguration, id string, artifact Artifact) error

Replace atomically updates one artifact receipt after its files have been materialized. It safely prunes stale, unchanged files from the previous receipt while retaining files claimed by another artifact.

func Save

func Save(config *schema.AtmosConfiguration, lock *LockFile) error

Save atomically replaces the committed lock with deterministic YAML.

Types

type Artifact

type Artifact struct {
	Name   string `yaml:"name,omitempty" json:"name,omitempty"`
	Kind   string `yaml:"kind" json:"kind"`
	Target string `yaml:"target" json:"target"`
	Source Source `yaml:"source" json:"source"`
	Files  []File `yaml:"files" json:"files"`
	Order  int    `yaml:"order" json:"order"`
	// IncludedPaths/ExcludedPaths are the copy-filter patterns in effect when this artifact was
	// recorded (see RecordOptions.IncludedPaths/ExcludedPaths). Omitted entirely for artifacts
	// recorded with no filtering (mixins, and unfiltered sources), so a committed lock file written
	// before these fields existed loads with both nil -- IsMaterialized treats that identically to
	// an explicit empty list, never spuriously reporting drift on an old receipt.
	IncludedPaths []string `yaml:"included_paths,omitempty" json:"included_paths,omitempty"`
	ExcludedPaths []string `yaml:"excluded_paths,omitempty" json:"excluded_paths,omitempty"`
}

Artifact is one independently materialized source, target, or mixin.

type CleanReport

type CleanReport struct {
	Removed   []string
	Conflicts []Drift
}

CleanReport summarizes a vendor clean operation.

func Clean

func Clean(config *schema.AtmosConfiguration, component string, force, dryRun bool) (*CleanReport, error)

Clean removes files owned by selected lock artifacts. A blank component selects every artifact. Modified files are preserved unless force is true. The lock is updated only when every selected artifact was removed cleanly.

type Drift

type Drift struct {
	Artifact string
	Path     string
	Reason   string
}

Drift reports a missing or changed lock-owned file.

func Verify

func Verify(config *schema.AtmosConfiguration, lock *LockFile) ([]Drift, error)

Verify compares lock-owned files with the current target tree and rejects lock targets that escape the configured project root.

type File

type File struct {
	Path   string `yaml:"path" json:"path"`
	Type   string `yaml:"type" json:"type"`
	Mode   uint32 `yaml:"mode" json:"mode"`
	SHA256 string `yaml:"sha256" json:"sha256"`
}

File records one lock-owned output path. SHA256 is the file bytes, or the symlink target text for a symlink.

func Inventory

func Inventory(root string) ([]File, error)

Inventory records every regular file and symlink below root with no exclusions at all (not even .git). Used by tests that need to assert exact directory contents after an operation; production code uses VendorInventory/VendorInventoryWithPatterns instead, both of which apply real skip rules.

func VendorInventory

func VendorInventory(root string) ([]File, error)

VendorInventory records the files that the standard directory vendoring copy writes. Git metadata is deliberately excluded because the installer never copies it to the materialized target.

func VendorInventoryWithPatterns

func VendorInventoryWithPatterns(root string, includedPaths, excludedPaths []string) ([]File, error)

VendorInventoryWithPatterns records the exact files selected by the shared vendor copy policy. It allows component.yaml sources to own only copied files, rather than taking a broad snapshot of a component directory that may also contain local configuration or mixin output.

type LockFile

type LockFile struct {
	Version   int                 `yaml:"version" json:"version"`
	Artifacts map[string]Artifact `yaml:"artifacts" json:"artifacts"`
}

LockFile is the versioned vendor.lock.yaml format.

func Load

func Load(config *schema.AtmosConfiguration) (*LockFile, error)

Load returns an empty lock when no lock file has been created yet.

func New

func New() *LockFile

New returns an empty lock file.

type MaterializationCheck

type MaterializationCheck struct {
	Materialized bool
	// Reason is empty when Materialized is true. Otherwise one of: "no lock entry", "target path
	// changed", "declared source changed", "included/excluded paths changed", or a per-file reason
	// naming the file (e.g. `file "foo.tf" missing`, `file "foo.tf" checksum mismatch`).
	Reason string
}

MaterializationCheck is IsMaterialized's structured result: whether a package's on-disk state still matches its vendor.lock.yaml receipt, and -- when it doesn't -- why.

func IsMaterialized

IsMaterialized reports whether a declared source (identity and copy-filter patterns alike) has a complete, unchanged installation receipt at target. It never treats cache metadata as evidence of integrity.

type MaterializationParams

type MaterializationParams struct {
	// ID is the lock artifact key -- see ArtifactID.
	ID string
	// Declared is the source's currently-declared URI (pre-redaction; IsMaterialized redacts it
	// itself before comparing against the receipt's already-redacted Source.Declared).
	Declared string
	// Target is the source's currently-declared destination path.
	Target string
	// IncludedPaths/ExcludedPaths are the source's currently-declared copy-filter patterns.
	IncludedPaths []string
	ExcludedPaths []string
}

MaterializationParams identifies the artifact IsMaterialized checks and the source's currently-declared identity and copy-filter patterns to compare against the lock receipt. A struct rather than positional parameters: with IncludedPaths/ExcludedPaths added to ID/Declared/ Target, this crosses the Options Pattern threshold (CLAUDE.md) of more than four parameters.

type RecordOptions

type RecordOptions struct {
	// IncludedPaths/ExcludedPaths select VendorInventoryWithPatterns-style filtered inventory,
	// matching a vendor.yaml or component.yaml source's own copy-filter configuration. Passed
	// through even when both are empty (an unfiltered patterned source still uses this path,
	// matching this package's existing behavior).
	IncludedPaths []string
	ExcludedPaths []string
	// Mixin marks a mixin install: inventoried via plain VendorInventory (no pattern filtering,
	// since mixins install a set of individually-declared files rather than a filtered directory
	// copy), and its filename is appended to ArtifactID's writer list so a component and its
	// mixins never collide on the same lock key.
	Mixin         bool
	MixinFilename string
	// HTTPMetadata is best-effort HTTP cache metadata (ETag/Last-Modified) captured during the
	// fetch that staged tempDir, when it was an HTTP(S) source -- see downloader.FetchMetadata's
	// doc comment. Zero-value for git, OCI, and local sources, whose fetch has no HTTP response to
	// observe. Cache metadata only: never read by IsMaterialized or Verify, both of which continue
	// to rely solely on Digest and the per-file SHA256 values for integrity/drift decisions.
	HTTPMetadata downloader.FetchMetadata
	// VersionConstraint/ResolvedVersion record a range-declared `version:`'s resolution -- see
	// pkg/vendoring/install/version_resolve.go. Both empty for an exact-pinned version: (the common
	// case), matching Source.VersionConstraint/ResolvedVersion's own omitempty fields.
	VersionConstraint string
	ResolvedVersion   string
}

RecordOptions configures how Record inventories and identifies a materialized artifact.

type RecordTarget

type RecordTarget struct {
	// Kind is the installer's PkgType.String() (e.g. "remote", "oci", "local").
	Kind string
	// Name is the vendor.yaml/component.yaml source's declared name.
	Name string
	// TempDir is the staged fetch content Record inventories.
	TempDir string
	// Path is the materialized destination (a vendor.yaml target or a component's path).
	Path string
	// DeclaredSource is the pre-fetch declared URI (oci:// restored, credentials still present --
	// Record redacts it via lockfile.RedactSource before it reaches the committed lock).
	DeclaredSource string
}

RecordTarget identifies the writer and destination Record is recording a receipt for. A struct rather than five positional string parameters: Options Pattern (CLAUDE.md) applies once a function has more than four parameters, counting ctx/atmosConfig/target/opts.

type Source

type Source struct {
	Declared     string `yaml:"declared" json:"declared"`
	Resolved     string `yaml:"resolved,omitempty" json:"resolved,omitempty"`
	Digest       string `yaml:"digest,omitempty" json:"digest,omitempty"`
	ETag         string `yaml:"etag,omitempty" json:"etag,omitempty"`
	LastModified string `yaml:"last_modified,omitempty" json:"last_modified,omitempty"`
	// VersionConstraint is the raw semver-range expression declared in a source's `version:` field
	// (e.g. "^1.0.0"), populated only when `version:` was a range rather than an exact pin. Empty
	// for every exact-pinned source -- the overwhelming common case. Distinct from Resolved above:
	// Resolved is the post-fetch resolved identity (e.g. a resolved commit/digest);
	// VersionConstraint/ResolvedVersion are pre-fetch version-range resolution provenance -- see
	// pkg/vendoring/install/version_resolve.go.
	VersionConstraint string `yaml:"version_constraint,omitempty" json:"version_constraint,omitempty"`
	// ResolvedVersion is the concrete version VersionConstraint last resolved to. Empty whenever
	// VersionConstraint is empty.
	ResolvedVersion string `yaml:"resolved_version,omitempty" json:"resolved_version,omitempty"`
}

Source identifies the immutable artifact that was installed.

Jump to

Keyboard shortcuts

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