Documentation
¶
Overview ¶
Package resolve resolves action refs to commit SHAs, recursively discovers transitive dependencies, and verifies commit reachability.
Index ¶
- Constants
- func IsInvalidSelfRepositoryRef(err error) bool
- func LooksLikeSHA(ref string) bool
- func ManifestImages(yml, action string) []uses.Image
- type AncestryStatus
- type CompositeLocalPathError
- type InvalidSelfRepositoryRefError
- type LookupIssue
- type MalformedNestedRefError
- type NestedUse
- type Option
- type ReachabilityStatus
- type Resolver
- func (r *Resolver) CheckAncestry(ctx context.Context, owner, repo, pinnedSHA, liveSHA string) (AncestryStatus, string)
- func (r *Resolver) CheckAncestryCause(ctx context.Context, owner, repo, pinnedSHA, liveSHA string) (AncestryStatus, string, error)
- func (r *Resolver) ContainerImages(refs []parserlock.ActionRef) []uses.Image
- func (r *Resolver) DiscoverContaining(ctx context.Context, owner, repo, sha, hintRef string) (tag, branch string, err error)
- func (r *Resolver) DiscoverContainingDefault(ctx context.Context, owner, repo, sha, hintRef, defaultBranch string) (tag, branch string, err error)
- func (r *Resolver) FireResolveProgress(done, total int)
- func (r *Resolver) GHClient() *ghapi.Client
- func (r *Resolver) GetBranchHead(ctx context.Context, owner, repo, name string) (ghapi.BranchHead, bool)
- func (r *Resolver) GetDefaultBranch(ctx context.Context, owner, repo string) string
- func (r *Resolver) Hostname() string
- func (r *Resolver) IsKnownTagObject(owner, repo, sha string) bool
- func (r *Resolver) LatestRef(ctx context.Context, owner, repo string) (string, error)
- func (r *Resolver) LikelyBranches(ctx context.Context, owner, repo, sha, ref, defaultBranch string) []ghapi.BranchHead
- func (r *Resolver) ListBranches(ctx context.Context, owner, repo string) ([]ghapi.BranchHead, error)
- func (r *Resolver) ListProtectedBranches(ctx context.Context, owner, repo string) []ghapi.BranchHead
- func (r *Resolver) ListReleaseBranches(ctx context.Context, owner, repo string) []ghapi.BranchHead
- func (r *Resolver) ListTagsForRepo(ctx context.Context, owner, repo string) ([]ghapi.TagEntry, error)
- func (r *Resolver) MatchingHeadRefs(ctx context.Context, owner, repo, prefix string) []ghapi.BranchHead
- func (r *Resolver) PeelTagObject(ctx context.Context, owner, repo, sha string) (commit string, ok bool)
- func (r *Resolver) ReadManifests(ctx context.Context, reqs []ghapi.ActionFileRequest) []ghapi.ActionFileResult
- func (r *Resolver) Redirect(owner, repo string, orig parserlock.ActionRef, canonical string)
- func (r *Resolver) RefNamesCommit(ctx context.Context, owner, repo, name, sha string) (bool, error)
- func (r *Resolver) RepoIDs(ctx context.Context, hostname, owner, repo string) (int64, int64, error)
- func (r *Resolver) ResolveAllRecursive(ctx context.Context, refs []parserlock.ActionRef) ([]dep.Dependency, dep.ParentMap, error)
- func (r *Resolver) ReverseLookup(ctx context.Context, deps []dep.Dependency) (map[string]string, []LookupIssue, error)
- func (r *Resolver) SeedBranchHints(deps []dep.Dependency)
- func (r *Resolver) SeedFromLockfile(deps []dep.Dependency)
- func (r *Resolver) SeedHosts(deps []dep.Dependency) error
- func (r *Resolver) Seeded(ref parserlock.ActionRef) bool
Constants ¶
const DefaultMaxRecursionDepth = 10
DefaultMaxRecursionDepth matches the runner's composite action recursion limit.
Variables ¶
This section is empty.
Functions ¶
func IsInvalidSelfRepositoryRef ¶ added in v0.1.6
IsInvalidSelfRepositoryRef reports whether err contains an invalid nested self repository reference.
func LooksLikeSHA ¶ added in v0.1.0
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.
func ManifestImages ¶ added in v0.3.0
ManifestImages returns the unpinned images the action manifest yml runs: a Docker action's `runs.image` (a registry image or a Dockerfile it builds), or a composite's `docker://` steps. action names it as owner/repo[/path]@ref.
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 GitHub didn't answer (an outage or rate limit). 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 reports a `./…` use inside a remote composite. The path names the runner workspace, not the composite's repository, so it is never followed or locked. It is a warning carried on the resolver's error; callers separate it with SplitLocalPaths.
func SplitLocalPaths ¶ added in v0.3.0
func SplitLocalPaths(err error) (local []*CompositeLocalPathError, rest error)
SplitLocalPaths separates the CompositeLocalPathErrors joined into err from the errors that remain. rest is nil when only local paths were reported.
func (*CompositeLocalPathError) Error ¶ added in v0.1.4
func (e *CompositeLocalPathError) Error() string
type InvalidSelfRepositoryRefError ¶ added in v0.1.6
InvalidSelfRepositoryRefError is returned when a fetched composite carries the invalid `$/…@ref` form.
func (*InvalidSelfRepositoryRefError) Error ¶ added in v0.1.6
func (e *InvalidSelfRepositoryRefError) Error() string
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 MalformedNestedRefError ¶ added in v0.3.0
MalformedNestedRefError is returned when a fetched composite's `uses:` names a remote action the parser can't accept. It is never skipped: the composite's dependencies would be locked without it.
func (*MalformedNestedRefError) Error ¶ added in v0.3.0
func (e *MalformedNestedRefError) Error() string
type NestedUse ¶ added in v0.3.0
type NestedUse struct {
Ref parserlock.ActionRef
FetchRef string
}
NestedUse is an action to read: Ref as written, read at FetchRef when set.
func CompositeUses ¶ added in v0.3.0
func CompositeUses(parent dep.Dependency, yml string) ([]NestedUse, error)
CompositeUses returns the actions a composite's manifest uses, and the uses that must block rather than be skipped. `./…` uses are skipped and reported as CompositeLocalPathError. parent is the composite at its commit. A manifest that isn't a composite uses nothing.
type Option ¶
type Option func(*Resolver)
Option configures a Resolver at construction time. Pass to New.
func WithProfile ¶
WithProfile attaches profiling instrumentation.
func WithSleepFn ¶
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 ¶
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) CheckAncestryCause ¶ added in v0.3.0
func (r *Resolver) CheckAncestryCause(ctx context.Context, owner, repo, pinnedSHA, liveSHA string) (AncestryStatus, string, error)
CheckAncestryCause is CheckAncestry that also returns the error behind a result the Compare API didn't answer: an AncestryUnknown outage, or an AncestryNotAncestor refusal such as a 401 or 403. Only a transient error leaves ancestry unknown; any other answer leaves the commit unproven.
func (*Resolver) ContainerImages ¶ added in v0.3.0
func (r *Resolver) ContainerImages(refs []parserlock.ActionRef) []uses.Image
ContainerImages returns the unpinned images that refs and the composites they reach run, from manifests this resolver already read. Entries seeded from the lockfile carry no manifest and are skipped.
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 ¶
FireResolveProgress fires OnResolveProgress. Safe from multiple goroutines.
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 ¶
GetDefaultBranch returns the default branch name for owner/repo.
func (*Resolver) IsKnownTagObject ¶
IsKnownTagObject reports whether (owner, repo, sha) is already cached as an annotated tag object. Cache-only — never issues a network call.
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 ¶
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) ReadManifests ¶ added in v0.3.0
func (r *Resolver) ReadManifests(ctx context.Context, reqs []ghapi.ActionFileRequest) []ghapi.ActionFileResult
ReadManifests reads action.yml at each request's Ref. Results align with reqs and are not cached.
func (*Resolver) Redirect ¶ added in v0.2.0
func (r *Resolver) Redirect(owner, repo string, orig parserlock.ActionRef, canonical string)
Redirect re-labels the entry seeded for owner/repo under its canonical name, keeping the locked commit: a rename of the same repository is no reason to advance. orig is the ref as written, which the rewrite must match exactly. Unseeded refs are left to live resolution.
func (*Resolver) RefNamesCommit ¶ added in v0.3.0
RefNamesCommit reports whether `uses: owner/repo@name` would run exactly sha: name is recordable and, looked up the way the Actions backend looks it up (tag first, then branch), points at sha now. Repairing a full-SHA `uses:` to a recorded ref goes through it, whether that ref was recorded as a tag or a branch.
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. Exact tags take precedence over branch heads. A containing branch remains metadata when its head differs from SHA, so historical pins on the same branch keep distinct refs. 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 --relock: seeding would hide ref movement.