Documentation
¶
Overview ¶
Package sync provides component synchronization and locking operations.
This package coordinates the download, verification, and installation of source-based components (collectors and tools) from registries.
Key operations:
- Sync: download and verify components from lockfile
- Lock: resolve versions and create/update lockfile entries
Security features:
- Sigstore signature verification
- Digest verification against lockfile
- Config/lockfile alignment validation (anti-retargeting)
- Insecure install markers for audit trail
Index ¶
- func BuildGitHubRefTag(version string) string
- func BuildGitHubRepoURL(owner, repo string) string
- func BuildSourceURI(owner, repo string) string
- func CheckInsecureMarkerAllowed(name string, kind componenttypes.ComponentKind, binaryPath string, ...) error
- func ClearInsecureMarker(installDir string)
- func ComputeDigest(path string) (string, error)
- func HasInsecureMarker(installDir string) bool
- func InstallPath(baseDir string, kind componenttypes.ComponentKind, ...) (string, error)
- func MatchSigner(result *SigstoreResult, expected *componenttypes.LockedSigner) error
- func ParseSourceURI(source string) (owner, repo string, err error)
- func ResolveBinaryPath(baseDir, collectorName string, cfg config.CollectorConfig, ...) (string, error)
- func ResolveRemoteBinaryPath(baseDir, remoteName string, cfg config.RemoteConfig, lf *lockfile.LockFile) (string, error)
- func ResolveToolBinaryPath(baseDir, toolName string, cfg config.ToolConfig, lf *lockfile.LockFile) (string, error)
- func SanitizeAssetName(assetName string) (string, error)
- func VerifyDigest(path, expected string) error
- func WriteInsecureMarker(installDir string) error
- type AssetInfo
- type AssetNotFoundError
- type BundleNotFoundError
- type DefaultDigestVerifier
- type DefaultInstaller
- type DefaultSigstoreVerifier
- type DigestVerifier
- type ExpectedIdentity
- type GitHubRegistry
- func (r *GitHubRegistry) DownloadAsset(ctx context.Context, url, destPath string) error
- func (r *GitHubRegistry) FetchRelease(ctx context.Context, source, version string) (*ReleaseInfo, error)
- func (r *GitHubRegistry) FindBinaryAsset(release *ReleaseInfo, componentName, goos, goarch string) (*AssetInfo, error)
- func (r *GitHubRegistry) FindSigstoreBundle(release *ReleaseInfo, binaryAssetName string) (*AssetInfo, error)
- func (r *GitHubRegistry) Name() string
- func (r *GitHubRegistry) ResolveVersion(ctx context.Context, source, constraint string) (string, error)
- type Installer
- type LockOpts
- type LockResult
- type Locker
- type RegistryClient
- type ReleaseInfo
- type SigningInfo
- type SigstoreResult
- type SigstoreVerifier
- type SyncOpts
- type SyncResult
- type Syncer
- func (s *Syncer) Sync(ctx context.Context, cfg *config.JobConfig, opts SyncOpts) ([]SyncResult, error)
- func (s *Syncer) SyncRemote(ctx context.Context, name string, cfg config.RemoteConfig, ...) (*SyncResult, error)
- func (s *Syncer) ValidateAlignment(cfg *config.JobConfig, lf *lockfile.LockFile) error
- func (s *Syncer) VerifyExternalCollector(name string, cfg config.CollectorConfig, lf *lockfile.LockFile, ...) (*SyncResult, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildGitHubRefTag ¶
BuildGitHubRefTag constructs "refs/tags/version" from a version string.
func BuildGitHubRepoURL ¶
BuildGitHubRepoURL constructs "https://github.com/owner/repo" from components.
func BuildSourceURI ¶
BuildSourceURI constructs "github.com/owner/repo" from components.
func CheckInsecureMarkerAllowed ¶
func CheckInsecureMarkerAllowed(name string, kind componenttypes.ComponentKind, binaryPath string, frozen, allowInsecure bool) error
CheckInsecureMarkerAllowed checks if executing a component with an insecure marker is allowed. Returns nil if allowed, or an error if the marker exists and execution is disallowed.
Policy:
- In frozen mode: never allowed (security requirement)
- In non-frozen mode: requires allowInsecure=true
func ClearInsecureMarker ¶
func ClearInsecureMarker(installDir string)
ClearInsecureMarker removes the insecure install marker from the given directory. This is called after a secure verification to remove stale markers. Errors are ignored since the marker may not exist.
func ComputeDigest ¶
ComputeDigest computes sha256 digest of a file.
func HasInsecureMarker ¶
HasInsecureMarker checks if the given install directory has the insecure marker.
func InstallPath ¶
func InstallPath(baseDir string, kind componenttypes.ComponentKind, name, version, binaryName string) (string, error)
InstallPath returns deterministic install location for source-based components. All path components are validated to prevent path traversal attacks.
func MatchSigner ¶
func MatchSigner(result *SigstoreResult, expected *componenttypes.LockedSigner) error
MatchSigner checks that verification result matches expected signer.
func ParseSourceURI ¶
ParseSourceURI parses "github.com/owner/repo" into owner and repo components. This is the lockfile format (no version). SECURITY: Error messages use %q to escape untrusted input, preventing log injection.
func ResolveBinaryPath ¶
func ResolveBinaryPath(baseDir, collectorName string, cfg config.CollectorConfig, lf *lockfile.LockFile) (string, error)
ResolveBinaryPath resolves a collector binary path from config + lockfile. For source-based collectors, it returns deterministic install path. For external collectors, it returns the configured absolute binary path.
func ResolveRemoteBinaryPath ¶
func ResolveRemoteBinaryPath(baseDir, remoteName string, cfg config.RemoteConfig, lf *lockfile.LockFile) (string, error)
ResolveRemoteBinaryPath resolves a remote adapter binary path from config + lockfile. For source-based remotes, it returns deterministic install path. For external remotes, it returns the configured absolute binary path. For adapter-only remotes (no source or binary), it returns empty string (use PATH discovery).
func ResolveToolBinaryPath ¶
func ResolveToolBinaryPath(baseDir, toolName string, cfg config.ToolConfig, lf *lockfile.LockFile) (string, error)
ResolveToolBinaryPath resolves a tool binary path from config + lockfile. For source-based tools, it returns deterministic install path. For external tools, it returns the configured absolute binary path.
func SanitizeAssetName ¶
SanitizeAssetName validates and extracts just the base filename from an asset name. This prevents path traversal attacks via malicious release asset names. Returns an error if the asset name is empty, contains path separators, or is unsafe.
func VerifyDigest ¶
VerifyDigest checks that a file matches the expected digest.
func WriteInsecureMarker ¶
WriteInsecureMarker creates the insecure install marker in the given directory. Uses safefile.WriteFilePrivate to refuse to follow symlinks (O_NOFOLLOW).
SECURITY: All errors are returned, not just symlink errors. If the marker cannot be written (disk full, permissions, etc.), the caller must not proceed with the insecure installation, otherwise the install will appear legitimate to HasInsecureMarker() checks later.
Types ¶
type AssetInfo ¶
type AssetInfo struct {
// Name is the asset filename.
Name string
// URL is the download URL for this asset.
URL string
// Size is the asset size in bytes (0 if unknown).
Size int64
// Platform is the target platform (e.g., "linux/amd64").
// Empty if the asset is not platform-specific.
Platform string
// IsSigstoreBundle indicates this is a .sigstore.json bundle.
IsSigstoreBundle bool
}
AssetInfo contains metadata about a release asset.
type AssetNotFoundError ¶
AssetNotFoundError indicates a binary asset was not found for a platform.
func (*AssetNotFoundError) Error ¶
func (e *AssetNotFoundError) Error() string
type BundleNotFoundError ¶
type BundleNotFoundError struct {
BinaryAsset string
}
BundleNotFoundError indicates a Sigstore bundle was not found.
func (*BundleNotFoundError) Error ¶
func (e *BundleNotFoundError) Error() string
type DefaultDigestVerifier ¶
type DefaultDigestVerifier struct{}
DefaultDigestVerifier is the production DigestVerifier.
func (DefaultDigestVerifier) Verify ¶
func (DefaultDigestVerifier) Verify(path, expectedDigest string) error
Verify implements DigestVerifier using VerifyDigest.
type DefaultInstaller ¶
type DefaultInstaller struct{}
DefaultInstaller is the production Installer using filesystem operations.
func (DefaultInstaller) Exists ¶
func (DefaultInstaller) Exists(installPath string) bool
Exists implements Installer using os.Stat.
func (DefaultInstaller) Install ¶
func (DefaultInstaller) Install(tmpPath, installPath string) error
Install implements Installer by making the binary executable and renaming atomically.
func (DefaultInstaller) Verify ¶
func (DefaultInstaller) Verify(installPath, expectedDigest string) error
Verify implements Installer using VerifyDigest.
type DefaultSigstoreVerifier ¶
type DefaultSigstoreVerifier struct{}
DefaultSigstoreVerifier is the production SigstoreVerifier.
func (DefaultSigstoreVerifier) Verify ¶
func (DefaultSigstoreVerifier) Verify(bundlePath, binaryPath string, expectedIdentity *ExpectedIdentity) (*SigstoreResult, error)
Verify implements SigstoreVerifier using VerifySigstoreBundle.
type DigestVerifier ¶
type DigestVerifier interface {
// Verify computes the SHA-256 digest of a file and compares it to expected.
// Returns nil if match, error if mismatch or read failure.
Verify(path, expectedDigest string) error
}
DigestVerifier abstracts digest verification for testability.
type ExpectedIdentity ¶
type ExpectedIdentity = sigstore.ExpectedIdentity
ExpectedIdentity specifies the expected source identity for signature verification.
type GitHubRegistry ¶
type GitHubRegistry struct {
// contains filtered or unexported fields
}
GitHubRegistry adapts github.Client to the RegistryClient interface.
func NewGitHubRegistry ¶
func NewGitHubRegistry() *GitHubRegistry
NewGitHubRegistry creates a RegistryClient backed by GitHub.
func NewGitHubRegistryWithClient ¶
func NewGitHubRegistryWithClient(client *github.Client) *GitHubRegistry
NewGitHubRegistryWithClient injects a github.Client for tests and alternate transports.
func (*GitHubRegistry) DownloadAsset ¶
func (r *GitHubRegistry) DownloadAsset(ctx context.Context, url, destPath string) error
DownloadAsset downloads a release asset to the specified path.
func (*GitHubRegistry) FetchRelease ¶
func (r *GitHubRegistry) FetchRelease(ctx context.Context, source, version string) (*ReleaseInfo, error)
FetchRelease fetches release metadata for a specific version.
func (*GitHubRegistry) FindBinaryAsset ¶
func (r *GitHubRegistry) FindBinaryAsset(release *ReleaseInfo, componentName, goos, goarch string) (*AssetInfo, error)
FindBinaryAsset finds the binary asset for a specific platform. This is a convenience method that wraps the underlying client. Returns a copy of the asset to avoid pointer aliasing issues.
func (*GitHubRegistry) FindSigstoreBundle ¶
func (r *GitHubRegistry) FindSigstoreBundle(release *ReleaseInfo, binaryAssetName string) (*AssetInfo, error)
FindSigstoreBundle finds the Sigstore bundle for a binary asset. Returns a copy of the asset to avoid pointer aliasing issues.
func (*GitHubRegistry) Name ¶
func (r *GitHubRegistry) Name() string
Name returns the stable registry identifier used in resolution and lockfile metadata.
func (*GitHubRegistry) ResolveVersion ¶
func (r *GitHubRegistry) ResolveVersion(ctx context.Context, source, constraint string) (string, error)
ResolveVersion resolves a version constraint to a concrete version. For GitHub, this uses semver constraint matching against available releases.
type Installer ¶
type Installer interface {
// Install writes a binary to the install path with proper permissions.
// Returns error if installation fails.
Install(tmpPath, installPath string) error
// Verify checks if an installed binary matches the expected digest.
// Returns nil if digest matches, error otherwise.
Verify(installPath, expectedDigest string) error
// Exists checks if a binary is already installed at the given path.
Exists(installPath string) bool
}
Installer abstracts local binary installation for testability. The default implementation writes to the filesystem.
type LockOpts ¶
type LockOpts struct {
Platforms []string // Platforms to lock (e.g., "linux/amd64"). Empty = current platform only.
AllPlatforms bool // Lock all available platforms from release.
}
LockOpts controls locking behavior.
type LockResult ¶
type LockResult struct {
Name string // Component name (collector, tool, or remote)
Kind string // "collector", "tool", or "remote"
Version string
Platforms []string
IsNew bool
Updated bool
}
LockResult contains the result of a lock operation.
type Locker ¶
type Locker struct {
Registry RegistryClient
LockfilePath string
BaseDir string // .epack directory
}
Locker resolves component sources and writes lockfile entries.
func NewLockerWithRegistry ¶
func NewLockerWithRegistry(registry RegistryClient, workDir string) *Locker
NewLockerWithRegistry creates a locker with a custom registry client. Useful for testing or multi-registry support.
func (*Locker) DetectAvailablePlatforms ¶
func (l *Locker) DetectAvailablePlatforms(release *ReleaseInfo, componentName string) []string
DetectAvailablePlatforms finds all platforms available in a release.
func (*Locker) LoadOrCreateLockfile ¶
LoadOrCreateLockfile loads the existing lockfile or creates a new one.
type RegistryClient ¶
type RegistryClient interface {
// Name returns the registry identifier (e.g., "github", "locktivity").
Name() string
// ResolveVersion resolves a version constraint to a concrete version.
// For example, "^1.0.0" might resolve to "v1.2.3".
// Returns the resolved version tag and any error.
ResolveVersion(ctx context.Context, source, constraint string) (string, error)
// FetchRelease fetches release metadata for a specific version.
// The source is registry-specific (e.g., "owner/repo" for GitHub).
FetchRelease(ctx context.Context, source, version string) (*ReleaseInfo, error)
// DownloadAsset downloads a release asset to the specified path.
DownloadAsset(ctx context.Context, url, destPath string) error
// FindBinaryAsset finds the binary asset for a specific platform.
// Returns the asset info or an error if not found.
FindBinaryAsset(release *ReleaseInfo, componentName, goos, goarch string) (*AssetInfo, error)
// FindSigstoreBundle finds the Sigstore bundle for a binary asset.
// Returns the bundle asset or an error if not found.
FindSigstoreBundle(release *ReleaseInfo, binaryAssetName string) (*AssetInfo, error)
}
RegistryClient is the interface for resolving and fetching components. Implementations include GitHub (default) and future registries like Locktivity.
type ReleaseInfo ¶
type ReleaseInfo struct {
// Version is the resolved version tag (e.g., "v1.2.3").
Version string
// Assets contains platform-specific binaries and their metadata.
Assets []AssetInfo
// SigningInfo contains Sigstore signing metadata if available.
SigningInfo *SigningInfo
}
ReleaseInfo contains metadata about a component release. This is a registry-agnostic representation of release data.
type SigningInfo ¶
type SigningInfo struct {
// Issuer is the OIDC issuer that authenticated the signer.
Issuer string
// Subject is the certificate subject (e.g., workflow path).
Subject string
// SourceRepositoryURI is the source repository URI from the certificate.
SourceRepositoryURI string
// SourceRepositoryRef is the source repository ref from the certificate.
SourceRepositoryRef string
}
SigningInfo contains Sigstore signing metadata.
type SigstoreResult ¶
SigstoreResult contains verified signer identity from Sigstore bundle.
func VerifySigstoreBundle ¶
func VerifySigstoreBundle(bundlePath, artifactPath string, expected *ExpectedIdentity) (*SigstoreResult, error)
VerifySigstoreBundle verifies a Sigstore bundle against an artifact. Returns the verified signer identity claims.
type SigstoreVerifier ¶
type SigstoreVerifier interface {
// Verify verifies a Sigstore bundle against a binary and expected identity.
// Returns signing result on success, error on verification failure.
Verify(bundlePath, binaryPath string, expectedIdentity *ExpectedIdentity) (*SigstoreResult, error)
}
SigstoreVerifier abstracts Sigstore bundle verification for testability.
type SyncOpts ¶
type SyncOpts struct {
Frozen bool // Verify only, don't download.
InsecureSkipVerify bool // Skip Sigstore verification (NOT RECOMMENDED).
InsecureTrustOnFirst bool // Trust digest from lockfile without Sigstore (NOT RECOMMENDED).
}
SyncOpts controls sync behavior.
type SyncResult ¶
type SyncResult struct {
Name string // Component name
Kind string // "collector" or "tool"
Version string
Platform string
Installed bool
Verified bool
Skipped bool // External binary, skipped
}
SyncResult contains the result of syncing a component.
type Syncer ¶
type Syncer struct {
Registry RegistryClient
LockfilePath string
BaseDir string // .epack directory
}
Syncer downloads components from lockfile.
func NewSyncerWithRegistry ¶
func NewSyncerWithRegistry(registry RegistryClient, workDir string) *Syncer
NewSyncerWithRegistry creates a syncer with a custom registry client. Useful for testing or multi-registry support.
func (*Syncer) Sync ¶
func (s *Syncer) Sync(ctx context.Context, cfg *config.JobConfig, opts SyncOpts) ([]SyncResult, error)
Sync downloads and verifies all components for the current platform.
func (*Syncer) SyncRemote ¶
func (s *Syncer) SyncRemote(ctx context.Context, name string, cfg config.RemoteConfig, lf *lockfile.LockFile, platform string, opts SyncOpts) (*SyncResult, error)
SyncRemote syncs a single remote adapter. This is the exported version for use by other packages that need to install a specific remote adapter on-demand.
func (*Syncer) ValidateAlignment ¶
ValidateAlignment checks that config and lockfile collectors match. SECURITY: This validates that the config source matches the lockfile source, preventing "lockfile retargeting" attacks where an attacker modifies the config to point to a different repository while reusing a valid lockfile entry.
func (*Syncer) VerifyExternalCollector ¶
func (s *Syncer) VerifyExternalCollector(name string, cfg config.CollectorConfig, lf *lockfile.LockFile, platform string, opts SyncOpts) (*SyncResult, error)
VerifyExternalCollector verifies an external binary against lockfile.