You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Trace every locked commit to its recorded ref - #186
Every locked commit is now checked, in every mode, against the history of its recorded tag or branch, looked up by exact name the way the Actions backend resolves it, so a fork-only commit can no longer pass under the upstream action's name (closes#174).
A recorded ref that was rewritten or deleted so it no longer contains the locked commit, a recorded ref that isn't a real tag or branch, and a malformed uses: now block with a clear message instead of passing silently; an exact tag that only moved ahead warns under --verify, and --relock --accept-moved re-records a direct full-SHA pin whose recorded ref no longer vouches for it.
Bugs already present in v0.2.0 that this work surfaced are fixed in the follow-up #197.
Recover local fix fcdd43df96c77d5a376a3c27de8d03f07f6317c5 and retain both community normalization safeguards.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Recorded tags now re-peel before repair (#174) and branch normalization
needs a head proof (#165), so same-run conflicting repairs can no longer
be planned. Fixtures ported from candidate commit 3eb0100.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Parity now resolves recorded branch heads and fails closed when the
recorded ref is inconclusive (#174). Stub fixtures ported from candidate
commits 3eb0100 and 22e894c.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CHECKOUT_SHA was the actions/checkout v6.0.2 commit while the fixtures
record it under v4 and main. Recorded-ref tracing (#174) correctly rejects
that; use the real v4.2.2 commit the stub tag list already names.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Restores the #167 same-run scenario with a recorded tag instead of
swapping it for a branch, which only exercised the missing-head exit.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the original --verify bodies, adjusted for ref-qualified lookups and
fail-closed inconclusive checks; replace the mode cross-products with one
default/--no-fix test, and drop full-SHA and entry-ref cases that
TestParityFinding_FullSHAKey and TestValidEntryRef already cover.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The backend resolver, not the runner, looks up and rejects lock entry
refs; say so in comments, docs and the missing-ref finding detail.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Tags move, and the Actions backend accepts a pin whose commit is still in
its tag's history. Every lock entry ref is now checked by reachability:
a tag that lost the commit still blocks and an inconclusive check still
fails closed, but a tag that moved ahead only warns under --verify.
Dropping the separate tag-equality lookup also saves the extra REST
commit call when a ref still points at its locked commit.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
An error-severity finding blocks the run, so it never renders as a
warning. Under --verify the terminal now shows an exact tag that moved
ahead of its locked commit, matching the JSON warning, and the
inconclusive-check remediation names the Actions backend.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A ref like main~1 or v1@{1} is not a tag or branch name, but a commit-ish
lookup evaluates it as a revision. Validate names with git
check-ref-format rules, matching actions-lockfile's RefName: an entry ref
that fails makes the lockfile unreadable, and parity never builds a
lookup expression from one.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
--relock drops findings for recorded pins because it replaces them, but
it also dropped them for pins it had just resolved, so it could write a
lock that the next --verify rejects.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A full-SHA entry whose recorded tag or branch no longer vouches for it
recommended --accept-moved, which then refused it. --accept-moved now
accepts it as a warning and re-records a tag or branch that contains the
commit, chosen by reverse lookup; a commit no branch contains still fails.
Fresh full-SHA pins are no longer checked against a pre-planning ref.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The Actions backend resolver looks a recorded ref up as a tag before a
branch, so reverse lookup now skips a containing branch whose name is
also a tag.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A ref counts only if a tag or branch exists by exactly that name: GraphQL
also asks ref(qualifiedName:), and REST reads git/ref/{tags|heads}/<name>.
Like the Actions backend, names ending in -g plus four or more hex
digits are not accepted as recorded or uses: refs, so an entry with one
makes the lockfile unreadable and a uses: ref with one is never locked.
Adapted from 2134d14 and 93b2f4a.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
--accept-moved now prints the old and new recorded ref when it keeps a
full-SHA pin's commit but records a new tag or branch for it. A ref this
run resolved that isn't a tag or branch is titled "Not a tag or branch";
"Ref no longer exists" is kept for a ref the lockfile recorded.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A tool failure now prints before the run log path instead of after it.
Inconclusive checks and the Dependabot proxy abort show a short cause on
the terminal, such as "could not check v4 history: GitHub returned 403
Forbidden"; --json and the run log keep the full error.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A full-SHA pin whose recorded tag or branch no longer exists was titled
"Pinned commit not in upstream history". It is now "Ref no longer
exists", like any recorded ref that is gone.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Tag precedence keyed off the tag peeling to a commit, so a tag that
targets a tree or blob fell through to a same-named branch and parity
checked the branch's history. Precedence now keys off the tag existing,
on both the GraphQL and REST paths; such a tag resolves to no commit.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reverse lookup filtered tag names with the backend rule only, and after
deciding whether to read more pages. An unrecordable tag on the first page
(release-g1234) then stopped the search for a recordable tag on a later
page, and SHA-shaped or refs/ tag and branch names could be chosen and
rejected later by the lockfile. Candidates now use RecordableRefName, the
same predicate as ValidEntryRef, before any paging or selection.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The planner's SHA repair picked the recorded branch when its head was the
locked commit, without the tag-shadow check reverse lookup does, so
rewriting to @main could name a same-named tag's commit instead. The
repair asks refCandidates, which now also applies the name policy and
the shadow check to that branch.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
--verify and --no-fix return before planning, so --accept-moved could
pass a full-SHA pin whose recorded ref is gone without ever finding or
validating a replacement. Only runs that write accept it.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The line search matched the first occurrence of the key, which is
usually the workflow's list item, or the prefix of a longer key. Match
the whole quoted mapping key instead.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replacement matching ignores workflow and original pin identity
cmd/gh-actions-lock/pin_summary.go:255
This matches any entry with the same repository and commit, even one from another workflow. If one workflow newly pins @v5 at commit A while a full-SHA pin elsewhere is repaired to record v6 at A, the summary can incorrectly report v5 as the accepted replacement. Setting seen then hides the actual repair. Match the finding's workflow and original pin or rewrite identity, not just its repository and commit.
SSO guidance is lost when shortening HTTP errors
internal/ghapi/brief.go:15
StatusCode unwraps SSORateLimitedError to its HTTP error, so this replaces its authorization guidance with only a status line. It also removes the SAML-enforcement message from ordinary 403 errors. Parity failures now block the run, but fix mode does not print the separate read-only SSO hints, leaving users without the required next step. Preserve actionable SSO messages while shortening other HTTP errors and omitting request URLs.
Tag lookup misses recorded tags beyond the first page
internal/pin/plan.go:663
LookupTag searches a cached listing backed by Client.ListTags, which reads only the first 100 tags. A full-SHA pin recorded under an older tag outside that page now silently skips normalization, even when that tag still points exactly at the locked commit. Use an exact lookup of the recorded tag and compare its peeled commit, rather than treating absence from the first page as absence upstream. Add coverage with the recorded tag beyond that page.
With --verify --relock or --verify --accept-moved, the relock filter discards this recorded RefMoved warning, while the freshly resolved pin already matches the live head. The diagnostic RefMoved finding has TagMoved=false, so the terminal suppresses it and verification succeeds without the documented moved-tag warning. Preserve this warning through the filter, and ensure warning deduplication keeps its TagMoved marker rather than the earlier diagnostic finding.
Relock can discard blocking parity failures after transient errors
internal/pipeline/parity.go:166
Under --relock outside the Dependabot proxy, resolution can fail transiently and leave a recorded symbolic pin without a fresh replacement. If parity also fails, keep(UnreachablePin, symbolicPin) is false here, and the next filter discards ReachabilityUnknown. Diagnosis leaves only a non-blocking resolution warning, so planning can retain the old pin and the command succeeds without verifying it. Keep recorded parity errors blocking even during relocking; cover a locked @v4 whose resolution and parity requests both return 503.
This new warning drops the transitive parent that parityFinding derives from lp.Parent. When an exact tag used inside a composite moves, the warning omits which composite requires it, and the JSON finding loses required_by. Pass the locked pin or its parent into movedTagFinding and populate ParentNWO and the detail suffix consistently with other parity findings.
Relock cannot follow moved tags for SHA-keyed pins
internal/pipeline/parity.go:298
For a full-SHA uses: whose recorded exact tag moved ahead, --relock resolves the SHA to the same commit. The new guard in narrowVerifiedEntries correctly refuses to rewrite it to the moved tag, so this command does not lock the tag's current commit and can leave the same warning on the next verification. For SHA-keyed pins, explain that following the tag requires changing uses:; retain the current advice for symbolic pins.
Mixed direct and composite SHA pins leave stale state
internal/pipeline/run.go:173
If a workflow uses both a composite and the same full-SHA child directly, Closure now reports the child with no parent, so --accept-moved downgrades its failed check here. Planning can normalize only the direct use to a tag, while State.Set retains the composite's edge to the original SHA entry and leaves that entry's recorded ref unchanged. The command succeeds, but the next --verify rejects the child again. Repair the original SHA-keyed entry too, or keep this case blocking; add a regression covering both consumers.
Repairing a full-SHA pin and reverse lookup can both look up the same
recorded ref by exact name. Cache found and missing answers for the
invocation and coalesce concurrent lookups; failed lookups are retried.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
v0.2.0 rewrote a full-SHA `uses:` to its recorded ref without proof. Since
#174 the repair requires proof, but only checked semver tags and branches:
a non-semver tag (recorded like a branch) was never normalized.
Repair now looks the recorded ref up by exact name, as the backend resolves
it (tag first), and rewrites only when it names the locked commit. A moved
tag, a branch a tag shadows, or a containing branch is left as a SHA.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The --accept-moved re-record line matched pinned entries by repository and
commit, so another workflow's pin of the same commit under a different ref
could be reported as the new recorded ref. Match the finding's own lock
key, kept or rewritten from it.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A --verify warning for a tag that moved ahead of a composite's pin did not
name the composite (no required_by), and a full-SHA pin was told to run
--relock, which never changes a full-SHA `uses:`, so the warning stayed.
Name the parent like other parity findings. Advise a full-SHA pin to point
`uses:` at the tag, or, for a composite's pin, to upgrade the composite.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
LookupRefName, and ResolveRefName through it, read refs on the routing
client instead of the repository's selected host, so on a tenant host
SHA-pin repair crashed. Route it like every other repository method, and
test every exported repository method on a tenant client so a new one
can't skip host selection.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Relock can retain unverified commits, and accepted SHA-pin repairs can preserve invalid entries or delete pins and their children.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Match diagnostic keys without lowercasing ref names
internal/lockfile/state.go:74
Lowercasing the entire key makes this diagnostic confuse distinct Git refs. If entries for owner/repo@Main and owner/repo@main exist and only the latter has an invalid ref, this returns the line of @Main instead. Match the original mapping key without folding its ref's case.
The diagnostic line lookup lowercased the whole key, so with entries for
owner/repo@V1 and owner/repo@v1 it could cite the wrong one. Compare
canonical pin keys instead (parserlock.ParsePin): owner and repo fold,
refs stay case-sensitive, as everywhere else the lockfile is keyed.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every locked commit is now checked, in every mode, against the history of its recorded tag or branch, looked up by exact name the way the Actions backend resolves it, so a fork-only commit can no longer pass under the upstream action's name (closes #174).
A recorded ref that was rewritten or deleted so it no longer contains the locked commit, a recorded ref that isn't a real tag or branch, and a malformed
uses:now block with a clear message instead of passing silently; an exact tag that only moved ahead warns under--verify, and--relock --accept-movedre-records a direct full-SHA pin whose recorded ref no longer vouches for it.Bugs already present in v0.2.0 that this work surfaced are fixed in the follow-up #197.