resolve

package
v0.1.7-rc.1 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package resolve resolves action refs to commit SHAs, recursively discovers transitive dependencies, and verifies commit reachability.

Index

Constants

View Source
const DefaultMaxRecursionDepth = 10

DefaultMaxRecursionDepth matches the runner's composite action recursion limit.

Variables

This section is empty.

Functions

func IsCompositeLocalPath added in v0.1.4

func IsCompositeLocalPath(err error) bool

IsCompositeLocalPath reports whether err (or any error in its chain) is a CompositeLocalPathError.

func IsInvalidSelfRepositoryRef added in v0.1.6

func IsInvalidSelfRepositoryRef(err error) bool

IsInvalidSelfRepositoryRef reports whether err contains an invalid nested self repository reference.

func LooksLikeSHA added in v0.1.0

func LooksLikeSHA(ref string) bool

LooksLikeSHA returns true when ref is a hex string of SHA-1 (40) or SHA-256 (64) length — i.e. the user wrote a bare commit hash.

Types

type AncestryStatus

type AncestryStatus int

AncestryStatus represents whether a pinned SHA is a legitimate ancestor of the live SHA.

const (
	// AncestryConfirmed means the pinned SHA is an ancestor of the live SHA.
	AncestryConfirmed AncestryStatus = iota
	// AncestryNotAncestor means the pinned SHA is NOT an ancestor — possible forgery.
	AncestryNotAncestor
	// AncestryUnknown means the check could not be completed (rate limit, API error).
	AncestryUnknown
)

type CompositeLocalPathError added in v0.1.4

type CompositeLocalPathError struct {
	// Parent is the NWO@Ref of the composite action containing the local path.
	Parent string
	// LocalPath is the ./… value found in the composite's steps.
	LocalPath string
}

CompositeLocalPathError is returned when a remote composite action uses a local path (./…) reference in its steps. We cannot resolve transitive dependencies behind such references, so the workflow must be blocked.

func (*CompositeLocalPathError) Error added in v0.1.4

func (e *CompositeLocalPathError) Error() string

type InvalidSelfRepositoryRefError added in v0.1.6

type InvalidSelfRepositoryRefError struct {
	Parent string
	Ref    string
}

InvalidSelfRepositoryRefError is returned when a fetched composite carries the invalid `$/…@ref` form.

func (*InvalidSelfRepositoryRefError) Error added in v0.1.6

type LookupIssue added in v0.1.0

type LookupIssue struct {
	Index   int    // position in the deps slice
	NWO     string // owner/repo
	Ref     string // original ref
	SHA     string // commit hash
	Message string // human-readable reason
}

LookupIssue describes a single dep that ReverseLookup could not resolve.

type Option

type Option func(*Resolver)

Option configures a Resolver at construction time. Pass to New.

func WithNowFn

func WithNowFn(fn func() time.Time) Option

WithNowFn overrides time.Now for rate-limit retry timing in tests.

func WithProfile

func WithProfile(p *profile.Session) Option

WithProfile attaches profiling instrumentation.

func WithSleepFn

func WithSleepFn(fn func(context.Context, time.Duration)) Option

WithSleepFn overrides the context-aware sleep used for rate-limit waits.

func WithTransport

func WithTransport(t http.RoundTripper) Option

WithTransport overrides the HTTP transport. Use in tests with httpmock.

type ReachabilityStatus

type ReachabilityStatus string

ReachabilityStatus represents the result of a commit reachability check.

const (
	// Reachable means the SHA is confirmed on the ref's lineage.
	Reachable ReachabilityStatus = "reachable"
	// Unreachable means the SHA is confirmed NOT on the ref's lineage
	// (e.g. it exists only in a fork network).
	Unreachable ReachabilityStatus = "unreachable"
	// ReachabilityUnknown means the check could not be completed
	// (timeout, rate limit, API error).
	ReachabilityUnknown ReachabilityStatus = "unknown"
)

type Resolver

type Resolver struct {

	// MaxRecursionDepth caps transitive composite action resolution depth.
	MaxRecursionDepth int

	// OnResolveProgress is called when a resolution batch makes progress.
	OnResolveProgress func(done, total int)

	// Pool is the shared worker pool for parallel resolution and reachability.
	Pool *pinpool.Pool
	// contains filtered or unexported fields
}

Resolver resolves action refs to commit SHAs.

func New

func New(hostname string, pool *pinpool.Pool, opts ...Option) (*Resolver, error)

New creates a Resolver for the given hostname and pool. Use With* options to inject a test transport, profiling, or test overrides.

func (*Resolver) CheckAncestry

func (r *Resolver) CheckAncestry(ctx context.Context, owner, repo, pinnedSHA, liveSHA string) (AncestryStatus, string)

CheckAncestry uses the Compare API to test whether pinnedSHA is an ancestor of liveSHA. This detects lockfile forgery: if someone injects a SHA that was never in the ref's lineage, merge_base(pinned, live) ≠ pinned.

func (*Resolver) DiscoverContaining

func (r *Resolver) DiscoverContaining(ctx context.Context, owner, repo, sha, hintRef string) (tag, branch string, err error)

hintRef may be empty (e.g. for bare-SHA pins). The repo's default branch is discovered automatically via GET /repos/{owner}/{repo} (cached).

func (*Resolver) DiscoverContainingDefault

func (r *Resolver) DiscoverContainingDefault(ctx context.Context, owner, repo, sha, hintRef, defaultBranch string) (tag, branch string, err error)

DiscoverContainingDefault is DiscoverContaining with an explicit hint at the repository's default branch (e.g. "main"). When the discovered branch set contains defaultBranch it is preferred over lexicographic ordering.

Branch search is two-phase. Phase 1 validates the likely/canonical set directly (literal ref, recorded hint branch, default branch, protected branches, release/v* branches) so a relevant branch is never missed because it sorts beyond the paginated listing cap. Phase 2 — a full protected-first then all-branches scan — runs only when phase 1 finds nothing. An orphan error is returned only if both phases fail to place the commit.

func (*Resolver) FireResolveProgress

func (r *Resolver) FireResolveProgress(done, total int)

FireResolveProgress fires OnResolveProgress. Safe from multiple goroutines.

func (*Resolver) GHClient

func (r *Resolver) GHClient() *ghapi.Client

GHClient returns the unified API client.

func (*Resolver) GetBranchHead

func (r *Resolver) GetBranchHead(ctx context.Context, owner, repo, name string) (ghapi.BranchHead, bool)

GetBranchHead looks up a single branch by name.

func (*Resolver) GetDefaultBranch

func (r *Resolver) GetDefaultBranch(ctx context.Context, owner, repo string) string

GetDefaultBranch returns the default branch name for owner/repo.

func (*Resolver) Hostname

func (r *Resolver) Hostname() string

Hostname returns the GitHub host the resolver is targeting.

func (*Resolver) IsKnownTagObject

func (r *Resolver) IsKnownTagObject(owner, repo, sha string) bool

IsKnownTagObject reports whether (owner, repo, sha) is already cached as an annotated tag object. Cache-only — never issues a network call.

func (*Resolver) LatestRef

func (r *Resolver) LatestRef(ctx context.Context, owner, repo string) (string, error)

LatestRef returns the highest stable tag for an action repository.

func (*Resolver) LikelyBranches

func (r *Resolver) LikelyBranches(ctx context.Context, owner, repo, sha, ref, defaultBranch string) []ghapi.BranchHead

LikelyBranches assembles the high-trust candidate set validated before any full branch scan: the literal ref (when it is a branch), the recorded lockfile hint branch, the default branch, protected branches and release/v* branches. Deduplicated by name; order is most-trusted first.

func (*Resolver) ListBranches

func (r *Resolver) ListBranches(ctx context.Context, owner, repo string) ([]ghapi.BranchHead, error)

ListBranches returns all branches for owner/repo.

func (*Resolver) ListProtectedBranches

func (r *Resolver) ListProtectedBranches(ctx context.Context, owner, repo string) []ghapi.BranchHead

ListProtectedBranches returns branches with protection rules enabled.

func (*Resolver) ListReleaseBranches

func (r *Resolver) ListReleaseBranches(ctx context.Context, owner, repo string) []ghapi.BranchHead

ListReleaseBranches returns release/v* branches (the canonical action publication branches) by matching heads/v and heads/release. Best-effort; cached per owner/repo.

func (*Resolver) ListTagsForRepo

func (r *Resolver) ListTagsForRepo(ctx context.Context, owner, repo string) ([]ghapi.TagEntry, error)

ListTagsForRepo returns all tags for owner/repo.

func (*Resolver) MatchingHeadRefs

func (r *Resolver) MatchingHeadRefs(ctx context.Context, owner, repo, prefix string) []ghapi.BranchHead

MatchingHeadRefs returns branches whose name starts with prefix.

func (*Resolver) PeelTagObject

func (r *Resolver) PeelTagObject(ctx context.Context, owner, repo, sha string) (commit string, ok bool)

PeelTagObject reports whether sha is an annotated tag object in owner/repo and, if so, the commit SHA it dereferences to. Tag-of-tag chains are peeled server-side. Returns ok=false for lightweight tags, plain commits, unknown SHAs, or any lookup failure (fail open).

func (*Resolver) RepoIDs

func (r *Resolver) RepoIDs(ctx context.Context, owner, repo string) (int64, int64, error)

RepoIDs returns the numeric owner ID and repo ID for a NWO.

func (*Resolver) ResolveAllRecursive

func (r *Resolver) ResolveAllRecursive(ctx context.Context, refs []parserlock.ActionRef) ([]dep.Dependency, dep.ParentMap, error)

ResolveAllRecursive resolves action refs and recursively discovers transitive dependencies from composite actions by reading their action.yml via GraphQL. The returned ParentMap (child dep key → parent dep keys) is owned by the caller and safe to mutate or hold across concurrent resolver calls.

func (*Resolver) ReverseLookup

func (r *Resolver) ReverseLookup(ctx context.Context, deps []dep.Dependency) (map[string]string, []LookupIssue, error)

ReverseLookup leaves symbolic refs unchanged and reverse-lookups bare SHA refs via DiscoverContaining. For bare SHAs it populates dep.Tag and dep.Branch and computes the canonical @ref. The ref priority is: tag (semver-ish release) > protected branch > default branch > any branch. When the canonical ref differs from dep.Ref the change is recorded in the returned rewrites map and dep.Ref is updated in place.

Bare SHA deps with no containing ref are skipped and reported in the returned issues slice. Only transient/API errors are returned as err.

func (*Resolver) SeedBranchHints

func (r *Resolver) SeedBranchHints(deps []dep.Dependency)

SeedBranchHints records a branch-of-record for each dep so subsequent containing-branch scans try that branch first. Hints from a previous lockfile are advisory: a miss falls through to a full branch scan.

func (*Resolver) SeedFromLockfile

func (r *Resolver) SeedFromLockfile(deps []dep.Dependency)

SeedFromLockfile pre-warms the resolution cache so repeat runs skip redundant API calls. Do NOT call with --rescan: seeding would hide ref movement.

Jump to

Keyboard shortcuts

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