actions: opt-in --resolve flag fills in the SHA each mutable @<ref> points at#57
Merged
Conversation
…> points at Closes the deferred follow-up from #47 (`actions audit`). `sakimori actions audit` was offline-only: it flagged `foo/bar@v1` as a mutable ref but left the user to manually look up what to pin to. New `--resolve` flag (off by default) hits the GitHub REST API and surfaces the resolved SHA on each finding so the user can copy-paste the fix straight from the report. Architecture: - `actions::Resolver` trait keeps the offline path the default and lets tests substitute a deterministic fake. - `actions::GithubResolver` is the concrete impl (`GET /repos/{owner}/{repo}/commits/{ref}` via ureq, reads `GITHUB_TOKEN` to raise the rate limit to 5000/hour). - `actions::resolve_all(&mut findings, &dyn Resolver)` walks findings, caches per `(owner, repo, ref)` so a workflow that uses `actions/checkout@v4` ten times only hits the API once, and populates `Finding::resolved_sha` (or `Finding::resolve_error` when the lookup fails — one rate-limited action shouldn't kill the whole audit). Output: - **text**: indented `→ resolved: <sha>` line under the finding; `→ resolve failed: <reason>` on lookup error. - **JSON**: new `resolved_sha` / `resolve_error` fields on `Finding` (both `skip_serializing_if = "Option::is_none"` so off-by-default consumers see no schema change). 5 new unit tests in `actions::tests` — caching, error isolation, owner/repo extraction edge cases, percent-encoding for `feature/x` style refs. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> Signed-off-by: bokuweb <[email protected]>
sakimori report
events by kind
denied samples (first 10)
📊 Open the full HTML report locallyrm -rf /tmp/sakimori-25654234782 && gh run download 25654234782 -R bokuweb/sakimori -n sakimori-report -D /tmp/sakimori-25654234782 && (open /tmp/sakimori-25654234782/sakimori-report.html 2>/dev/null || xdg-open /tmp/sakimori-25654234782/sakimori-report.html 2>/dev/null || echo "open file:///tmp/sakimori-25654234782/sakimori-report.html")Requires the |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Closes the deferred follow-up from #47 (
actions audit).sakimori actions auditwas offline-only: it flaggedfoo/bar@v1as a mutable ref but left the user to manually look up what to pin
to. New
--resolveflag (off by default) hits the GitHub REST APIand surfaces the resolved SHA on each finding so the user can
copy-paste the fix straight from the report.
sakimori actions audit --resolve .github/workflows/*.ymlArchitecture
actions::Resolvertrait keeps the offline path the default andlets tests substitute a deterministic fake.
actions::GithubResolveris the concrete impl:GET /repos/{o}/{r}/commits/{ref}via
ureq, readsGITHUB_TOKENto raise the rate limit to5000/hour.
actions::resolve_all(&mut findings, &dyn Resolver)walksfindings, caches per
(owner, repo, ref)so a workflow that usesactions/checkout@v4ten times only hits the API once, andpopulates
Finding::resolved_sha(orFinding::resolve_errorwhen the lookup fails — one rate-limited action shouldn't kill
the whole audit).
Schema additions
Findinggains twoOption<String>fields, bothskip_serializing_if = "Option::is_none"so off-by-defaultconsumers (no
--resolve) see no JSON-shape change:resolved_sha: 40-char hex when the lookup succeeded.resolve_error: human-readable reason when it failed(
HTTP 403,HTTP 404, network timeout, …).Test plan
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspace— 5 new unit tests inactions::tests:resolve_all_fills_sha_for_mutable_refs_and_skips_pinned_onesresolve_all_caches_repeated_lookupsresolve_all_records_error_per_finding_without_abortingfinding_owner_repo_extraction_handles_subpath_and_localurl_encode_ref_handles_slashes_and_pluses142 total in sakimori-core, all green.
sakimori actions audit --helpshows the new flagBuild succeeds on the (no-network) macOS dev box —
GithubResolver::newdoesn't make any calls untilresolve_allis invoked, so it's safe to construct.🤖 Generated with Claude Code