Skip to content

setup-mistkit: pin to resolved revision#380

Open
leogdion wants to merge 1 commit into
mainfrom
setup-mistkit-pin-revision
Open

setup-mistkit: pin to resolved revision#380
leogdion wants to merge 1 commit into
mainfrom
setup-mistkit-pin-revision

Conversation

@leogdion
Copy link
Copy Markdown
Member

@leogdion leogdion commented May 23, 2026

Summary

  • setup-mistkit writes revision: "<sha>" into Package.swift instead of branch: "<name>" so swift-build@v1's package-hash invalidates when MistKit advances.
  • Resolves the input branch via git ls-remote; falls back to branch: if resolution fails.
  • Already shipped on v1.0.0-beta.2 (Tag and validate ambiguous FieldValue scalar types (#375) #377); this lands the same change on main so consumers referencing @main (BushelCloud, CelestraCloud) pick it up.

Why

CelestraCloud PR brightdigit/CelestraCloud#36 was failing on every Linux/Windows job with errors like value of type 'RecordInfo' has no member 'get' and type '_ErrorCodeProtocol' has no member 'recordOperationFailed'. Root cause: swift-build@v1 hashes swift package dump-package for the SPM cache key. With branch: pinning, that JSON is constant for a given branch name, so a stale .build/ from before #372 (RecordResult) landed kept being restored. Macros macOS passes because Xcode DerivedData cache also keys on github.sha.

Test plan

  • CelestraCloud PR Reference Field Types #36 Ubuntu/Windows jobs pass on re-run after this PR merges
  • Stale-cache scenario (push a no-op commit to a feature branch of MistKit, re-run a consumer workflow) — verify cache miss happens

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated GitHub Actions setup workflow to provide more precise dependency pinning with automatic fallback mechanisms, improving build consistency and reliability across development platforms.

Review Change Stack

swift-build@v1's SPM cache key is hashed from `swift package dump-package`'s
canonical JSON. With the previous `branch: "<name>"` pin the dependency JSON
didn't change when the upstream branch advanced, so a new MistKit commit on
the same branch yielded a stale cache hit and consumer code that depended on
new MistKit symbols failed to compile against pre-existing cached binaries.

Resolve the input branch to its current HEAD commit via `git ls-remote` and
write `revision: "<sha>"` into Package.swift instead. The package hash now
changes whenever the branch moves, so the cache invalidates correctly. Falls
back to the original `branch:` pin if the ref can't be resolved.

This is the same shape as the explicit `git ls-remote` + cache-key fix that
already exists in CelestraCloud's update-feeds.yml, lifted into the shared
action so every consumer gets it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

The setup-mistkit GitHub action is updated to resolve branch names to commit SHAs and pin MistKit dependencies by revision: for reproducible builds, with graceful fallback to branch: pinning when commit resolution fails. Both Unix and Windows shell implementations are provided.

Changes

MistKit Dependency Pinning via Commit SHA

Layer / File(s) Summary
Action metadata and package dependency pinning logic
.github/actions/setup-mistkit/action.yml
Action description updated to reflect remote pinning to the branch's current commit. The composite action resolves the selected branch to its HEAD commit via git ls-remote and injects it into Package.swift as a revision: pin; Unix (bash + sed) and Windows (PowerShell + regex) implementations both include fallback to branch: pinning on resolution failure. Package.resolved is removed before proceeding.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit resolved to pin and persist,
Branch names to commits—no more drift or gist,
From git ls-remote to revision: it goes,
Both bash and PowerShell—wherever code flows,
With fallback in place, the build stands so strong! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'setup-mistkit: pin to resolved revision' directly and accurately describes the main change in the PR: updating the setup-mistkit action to pin MistKit dependencies to resolved SHA revisions instead of branch names.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch setup-mistkit-pin-revision

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown

claude Bot commented May 23, 2026

Code Review: PR #380 — setup-mistkit: pin to resolved revision

Overview

This PR fixes a stale SPM build-cache bug in consumer CI (CelestraCloud, BushelCloud). By resolving the branch to its current HEAD SHA and writing revision: "<sha>" instead of branch: "<name>", the swift package dump-package output — which swift-build@v1 hashes for its cache key — now changes whenever MistKit advances. The fallback to branch: on resolution failure is a sensible safety net.

The fix is correct and the motivation is well-understood. A few issues worth addressing before merge:


Bug: git ls-remote pattern is too broad

Unix step:

git ls-remote treats its last argument as a pattern matched against all ref names. Passing the bare branch name (e.g. "main") can match refs/heads/main, refs/tags/main, etc. With head -n1 you get whichever comes first — typically the branch, but not guaranteed if a same-named tag exists.

Recommendation: Scope to branches only:

Unix:

REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "refs/heads/$BRANCH" | head -n1 | cut -f1)

PowerShell:

$ref = (git ls-remote https://github.com/brightdigit/MistKit.git "refs/heads/$branch" | Select-Object -First 1) -split "`t" | Select-Object -First 1

Minor: sed delimiter collision

The sed substitution uses | as its delimiter. If a branch name contains a literal | (technically valid in git), the $REQ value injected into the sed command would corrupt it. SHA values are always hex so the revision: path is safe; only the branch: fallback path is at risk. Using a different delimiter (e.g. @) removes this edge case entirely.


Observation: silent fallback degradation

The fallback to branch: pin on resolution failure silently reverts to the pre-fix behaviour. A ::warning:: annotation would surface this in the Actions UI and help diagnose unexpected cache hits in consumer repos:

echo "::warning::Could not resolve $BRANCH to a commit; falling back to branch pin (cache may be stale)"

Positive notes

  • Both Unix and Windows implementations are updated consistently.
  • Deleting Package.resolved after rewriting Package.swift is correct.
  • The action description update accurately reflects the new behaviour.
  • Echo statements (Pinning MistKit to ... @ ...) are useful for diagnosing cache behaviour in run logs.
  • The fallback design is correct — a transient git ls-remote failure should not break the workflow.

Summary

Finding Severity
git ls-remote bare branch name matches tags and other refs, not just the branch Bug — a same-named tag silently pins to the wrong SHA
sed delimiter | collides with branch names containing | Minor / edge case
Fallback degrades silently without a visible warning Suggestion

The approach is correct. Scoping git ls-remote to refs/heads/ is the only change I would call blocking.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/actions/setup-mistkit/action.yml (1)

22-22: ⚡ Quick win

Reduce git ls-remote branch/tag ambiguity (currently low risk)

The MistKit remote currently shows no branch/tag name collisions, and git ls-remote ... main returns only refs/heads/main; so the head -n1 ambiguity concern is unlikely to occur in practice. Using refs/heads/$BRANCH is still a small intent-explicit improvement.

Suggested refinement for explicit branch matching
-        REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "$BRANCH" | head -n1 | cut -f1)
+        REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "refs/heads/$BRANCH" | head -n1 | cut -f1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/setup-mistkit/action.yml at line 22, The git ls-remote
invocation that sets REF should explicitly match branch refs to avoid tag/branch
ambiguity: update the command that assigns REF (the line using REF=$(git
ls-remote ... "$BRANCH" | head -n1 | cut -f1)) to query refs/heads/$BRANCH
instead of just "$BRANCH" so it only returns branch refs; keep the rest of the
pipeline (head -n1 | cut -f1) intact to extract the commit SHA into REF.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/actions/setup-mistkit/action.yml:
- Line 22: The git ls-remote invocation that sets REF should explicitly match
branch refs to avoid tag/branch ambiguity: update the command that assigns REF
(the line using REF=$(git ls-remote ... "$BRANCH" | head -n1 | cut -f1)) to
query refs/heads/$BRANCH instead of just "$BRANCH" so it only returns branch
refs; keep the rest of the pipeline (head -n1 | cut -f1) intact to extract the
commit SHA into REF.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c1256399-2782-4011-8819-dd2a3fd8f497

📥 Commits

Reviewing files that changed from the base of the PR and between 2537f39 and 9c64535.

📒 Files selected for processing (1)
  • .github/actions/setup-mistkit/action.yml

@codecov
Copy link
Copy Markdown

codecov Bot commented May 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.66%. Comparing base (d11c6c5) to head (9c64535).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #380      +/-   ##
==========================================
- Coverage   68.95%   67.66%   -1.29%     
==========================================
  Files         111      111              
  Lines        2641     2641              
==========================================
- Hits         1821     1787      -34     
- Misses        820      854      +34     
Flag Coverage Δ
mistdemo-spm-macos ?
mistdemo-swift-6.2-jammy ?
mistdemo-swift-6.2-noble ?
mistdemo-swift-6.3-jammy ?
mistdemo-swift-6.3-noble ?
spm 67.24% <ø> (+0.07%) ⬆️
swift-6.1-jammy 67.24% <ø> (+0.07%) ⬆️
swift-6.1-noble 67.43% <ø> (+0.18%) ⬆️
swift-6.2-jammy 67.24% <ø> (-0.04%) ⬇️
swift-6.2-noble 67.28% <ø> (-0.19%) ⬇️
swift-6.3-jammy 67.24% <ø> (-0.23%) ⬇️
swift-6.3-noble 67.47% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@claude
Copy link
Copy Markdown

claude Bot commented May 26, 2026

Code Review

Overview

Replaces branch: with revision: (commit SHA) pinning in the setup-mistkit composite action to fix a stale-cache bug in swift-build@v1. The SPM cache key is derived from swift package dump-package, which is constant for a given branch name — meaning a new MistKit commit on the same branch would silently reuse a stale build cache. Pinning by revision makes the cache key content-addressed. Falls back to branch: if the SHA can't be resolved.

Root-cause fix: Clear, well-motivated, and the fallback is a sensible defensive choice.


Positives

  • Comment above the step explains the why clearly (cache key hashing, stale-cache scenario, macOS/Xcode DerivedData divergence) — exactly the kind of non-obvious reasoning worth preserving.
  • Both Unix (bash) and Windows (PowerShell) paths are handled consistently.
  • Graceful fallback when git ls-remote fails or returns nothing.
  • Description update on action.yml accurately reflects the new behavior.

Suggestions / Issues

1. No timeout on git ls-remote (minor)

git ls-remote will block indefinitely if the network is unresponsive. Every CI run touching this action pays the latency:

# Unix
REF=$(timeout 10 git ls-remote https://github.com/brightdigit/MistKit.git "$BRANCH" 2>/dev/null | head -n1 | cut -f1)

# PowerShell — harder, but a job-level timeout on the step is an alternative

A 10-second timeout keeps CI fast on network hiccups and falls through to the branch: fallback cleanly.

2. REF is not validated as a SHA (low risk, defensive suggestion)

cut -f1 from git ls-remote output should always be a 40-char hex string, but a guard would make the intent explicit and prevent surprises if the output format ever differs:

if [[ "$REF" =~ ^[0-9a-f]{40}$ ]]; then
  REQ='revision: "'"$REF"'"'
  ...

3. The | sed delimiter and branch names (theoretical)

$REQ is interpolated unquoted into the sed pattern that uses | as the delimiter. Git branch names cannot legally contain |, so this is safe in practice — but worth a note if the action is ever generalized.

4. Fallback log message could be more informative (cosmetic)

"Could not resolve $BRANCH to a commit; pinning by branch"

Consider adding that this degrades cache-invalidation behavior so the operator knows what they're accepting:

"Could not resolve $BRANCH to a commit; falling back to branch: pin (cache may not invalidate on new commits)"

5. Windows: $ref truthiness is correct

PowerShell's if ($ref) on an empty/null string behaves as expected. The Select-Object -First 1 handles extra whitespace from git ls-remote correctly.


Assessment

Approve with minor suggestions. The fix is correct and the fallback is sound. Items 1–2 above are worth considering before merging; 3–4 are cosmetic. No blocking issues.

@claude
Copy link
Copy Markdown

claude Bot commented May 26, 2026

Code Review: PR #380 — setup-mistkit: pin to resolved revision

Overview

This PR switches the setup-mistkit composite action from a branch: pin to a revision: (commit SHA) pin by resolving the branch HEAD via git ls-remote at workflow time. This is a sound fix for the stale-cache problem caused by swift-build@v1 hashing swift package dump-package output, which is constant for a given branch name regardless of its current commit. Both Unix (bash) and Windows (PowerShell) paths are covered, and there's a sensible fallback to branch: when resolution fails.


Issues / Concerns

1. Potential shell injection — inputs.branch interpolated into a shell string

Severity: Medium

BRANCH='${{ inputs.branch }}'

GitHub Actions expands ${{ inputs.branch }} before the shell sees the string. If a caller passes a branch name containing a single-quote character (e.g., it's-a-test), the shell assignment breaks:

BRANCH='it's-a-test'   # syntax error / injection point

Recommendation: Validate or sanitise the input before use, or pass it through an environment variable (GitHub's preferred escape hatch):

env:
  BRANCH: ${{ inputs.branch }}
run: |
  # Now $BRANCH is an env var, not a shell-expanded string — safe to use directly
  REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "$BRANCH" | head -n1 | cut -f1)

The same issue exists in the PowerShell step:

$branch = '${{ inputs.branch }}'

Use $env:BRANCH after setting it via env: instead.

2. git ls-remote ref-pattern can match tags as well as branches

git ls-remote <url> main matches any ref whose last path component is main — including refs/tags/main if such a tag exists. The head -n1 mitigates this, but the ordering isn't guaranteed to favour refs/heads/.

Recommendation: Use the full ref path to be unambiguous:

REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "refs/heads/$BRANCH" | head -n1 | cut -f1)

The PowerShell step has the same exposure.


Positive Notes

  • Description update accurately reflects the new behaviour — good housekeeping.
  • Fallback logic (branch: when resolution fails) is a sensible defensive measure; CI won't hard-fail due to network issues.
  • rm -f Package.resolved / Remove-Item -ErrorAction SilentlyContinue correctly purge the resolved file so SPM re-resolves against the pinned revision.
  • Inline comment block at the top of the step clearly explains why revision: is used instead of branch: — valuable for future maintainers.
  • PowerShell equivalent is implemented consistently with the bash path.

Summary

The core approach is correct and solves the real problem. The two items above (shell injection via unvalidated input interpolation, and ambiguous git ls-remote ref pattern) are worth addressing before merge, especially the injection risk — even though callers are trusted CI workflows today, actions that accept freeform string inputs should not bake them directly into shell strings.

@claude
Copy link
Copy Markdown

claude Bot commented May 26, 2026

Code Review — PR #380: setup-mistkit: pin to resolved revision

Overview

Small but impactful CI/CD fix. The root cause (SPM cache keyed on swift package dump-package output, which is constant for a given branch name even as the branch advances) was correctly diagnosed and the fix is minimal and well-targeted.

Changes

  • Runs git ls-remote to resolve the branch to its current HEAD SHA before patching Package.swift.
  • Pins with revision: "<sha>" instead of branch: "<name>", making the cache key content-addressed.
  • Falls back to branch: if resolution fails (e.g. offline CI runners), preserving existing behavior.
  • Both Unix (bash) and Windows (PowerShell) steps updated consistently.

Issues

None. The implementation is clean:

  • '${{ inputs.branch }}' is correct — GitHub Actions substitutes the expression before the shell sees it; single quotes only prevent further shell word-splitting.
  • The head -n1 | cut -f1 approach for extracting the SHA is robust (handles ambiguous refs by taking the first match, matching the git ls-remote man-page recommendation).
  • The PowerShell variant uses the same logic with idiomatic Select-Object -First 1 / -split.
  • Remove-Item -ErrorAction SilentlyContinue / rm -f on Package.resolved is unchanged and correct.
  • The added comment block clearly explains why revision: is used and documents the fallback — future maintainers won't have to rediscover this.

Summary

Clean, focused fix with correct fallback behavior. ✅

@claude
Copy link
Copy Markdown

claude Bot commented May 26, 2026

Code Review — setup-mistkit: pin to resolved revision (#380)

Small, targeted fix with clear motivation. A few notes:

Correctness: works correctly

  • git ls-remote ... | head -n1 | cut -f1 correctly isolates the SHA
  • The PowerShell equivalent splits on tab and takes the first token — correct
  • The fallback to branch: on resolution failure is the right defensive choice
  • rm -f Package.resolved ensures the SPM cache key reflects the new pinning

Minor: network latency on every CI setup step

git ls-remote https://github.com/brightdigit/MistKit.git "$BRANCH" is a network call added to every workflow that uses setup-mistkit. On a fast CI runner this is ~1-2 seconds, but it does add a transient-failure mode (GitHub unavailable) that didn't exist before. The fallback handles that gracefully, so it's not a blocking concern — just worth knowing.

Minor: head -n1 before cut -f1

The Unix form uses | head -n1 | cut -f1. If git ls-remote returns multiple matching refs (e.g. both refs/heads/main and refs/tags/main), head -n1 picks whichever the remote lists first, which is usually the branch. For tag/branch name collisions the behaviour is deterministic but potentially surprising. Not a real issue for this repo's naming conventions; noting it for completeness.


Clean fix — the root cause (SPM cache keyed on constant JSON when branch: is used) is well-explained in the PR description and the fix is minimal. Good to merge.

@claude
Copy link
Copy Markdown

claude Bot commented May 26, 2026

Code Review

PR: setup-mistkit: pin to resolved revision
Summary: Replaces branch: SPM pinning with content-addressed revision: pinning by resolving the branch to its current HEAD commit via git ls-remote. Falls back to branch: if resolution fails.


Overview

This is a well-motivated fix for a real CI caching problem. swift-build@v1 hashes swift package dump-package for its SPM cache key; with branch: pinning that JSON is constant for a given branch name, so stale .build/ artifacts from previous MistKit commits are incorrectly restored. Switching to revision: makes the dependency content-addressed and forces a cache miss whenever MistKit advances. The cross-platform implementation (bash + PowerShell) is clean and the fallback behavior is sensible.


Correctness

  • Unix parsing is correct. git ls-remote … | head -n1 | cut -f1 reliably extracts the SHA from the first matching ref line.
  • PowerShell parsing is correct. Chaining Select-Object -First 1-split "\t"Select-Object -First 1` correctly picks the SHA column from the first output line.
  • Fallback path works. When $REF/$ref is empty, both branches fall back to branch: pinning, preserving existing behaviour in offline or network-restricted runners.

Issues & Suggestions

1. Missing --heads flag on git ls-remote (minor)

-REF=$(git ls-remote https://github.com/brightdigit/MistKit.git "$BRANCH" | head -n1 | cut -f1)
+REF=$(git ls-remote --heads https://github.com/brightdigit/MistKit.git "$BRANCH" | head -n1 | cut -f1)

Without --heads, the pattern could match tags or HEAD in addition to branches, causing an unexpected SHA to be chosen if a tag shares the branch name. This is unlikely in practice but worth tightening.

Same note for the PowerShell step:

-$ref = (git ls-remote https://github.com/brightdigit/MistKit.git $branch | Select-Object -First 1) -split "`t" | Select-Object -First 1
+$ref = (git ls-remote --heads https://github.com/brightdigit/MistKit.git $branch | Select-Object -First 1) -split "`t" | Select-Object -First 1

2. inputs.branch is expanded inline in the shell script (informational)

BRANCH='${{ inputs.branch }}'

GitHub Actions expands ${{ inputs.branch }} before the shell sees the script. If a caller passes a branch name containing shell metacharacters (e.g. a backtick or $(…)), this could lead to unexpected behaviour. Since inputs.branch is controlled by the calling workflow (not untrusted user input), the real-world risk is very low — but if this action is ever exposed to external triggers, wrapping the value in a validation step or using an environment variable intermediary would be safer.

3. Fallback log message could be more visible (nit)

The fallback prints to stdout (echo "Could not resolve …"), which may scroll past unnoticed. Consider >&2 or ::warning:: so it surfaces as a GitHub Actions annotation:

echo "::warning::Could not resolve $BRANCH to a commit; falling back to branch pin"

Test Coverage

No automated tests exist for this action (normal for CI plumbing). The PR description's manual test plan is appropriate — re-running a consumer workflow with a no-op MistKit commit to verify a cache miss is the right validation.


Summary

Approve with minor suggestions. The core change is correct and solves a real problem. Adding --heads to the git ls-remote calls is the only substantive suggestion; the rest are informational/nits.

🤖 Reviewed with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant