Skip to content

Releases: curlewlabs-com/local-cache

v3.2.0

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 03 Jul 03:16
2dbff87

What is new

Added — gc action for least-recently-used eviction (#38, closes #32)

A new curlewlabs-com/local-cache/gc action runs a scheduled sweep that evicts cold cache entries by last-use (--max-age-days, using the metadata mtime added in v3.1.0) and the per-runner restore-target copies they were rsynced to on each hit — the copies that otherwise accumulate unbounded alongside the store as version-keyed entries roll over.

It is race-free against concurrent saves and restores on the same machine: it takes the same per-key and per-target locks the save/restore paths hold (via curlewlabs-com/local-mutex), so evicting an entry can never corrupt a live rsync and reclaiming a target can never race a restore to it. As layered backstops, a target is spared if its owning entry is no longer cold or if anything under it was modified inside the window, and a live copy always keeps its entry. Default is a dry run (reports what would be reclaimed); pass apply: true to delete. See the README's gc section for the safety model and how to size max-age-days.

Changed

  • Restore now takes its per-key lock on the matched entry's own key — for a restore-keys (prefix) hit that is the resolved entry's stored key, not the requested key — so it is the exact lock the gc takes to evict that entry, closing a source-eviction race on prefix hits. Restore inputs and outputs are unchanged.
  • The restore / save / gc actions require curlewlabs-com/local-mutex v2.1.0+ (pinned) for its CLI surface.

No breaking changes — action.yml and save/action.yml inputs and outputs are unchanged. Consumers tracking @v3 get the restore improvement automatically; the new gc action is opt-in.

v3.1.0

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 19 Jun 05:09
cedfc94

What is new

Added — last-use tracking for eviction (#33)

Every restore now stamps the entry metadata file (.local-cache-key) mtime, including the constant-time marker-skip path, so an external least-recently-used sweep can reclaim entries by genuine recency of use rather than creation — without evicting hot ones. The entry directory mtime (which drives prefix / restore-keys selection) is deliberately left untouched, so selection order is unchanged. The README has a new Eviction section with a safe whole-entry sweep recipe.

Changed

  • Entry scripts now run set -eu (nounset), with guarded positionals so a missing argument still produces the friendly "must not be empty" error instead of an unbound-variable abort. (#34)
  • CI: bump actions/checkout to v6.0.3. (#30)

No breaking changes — action.yml and save/action.yml inputs and outputs are unchanged. Consumers tracking @v3 get this automatically.

v3.0.2

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 16 Apr 23:27

Summary

Docs-only release. No action behavior changes; @v3 consumers already received every code change through v3.0.1.

  • AGENTS.md release-tagging bullet now documents the actual contract (immutable patch tag + floating major tag + GitHub release per release), matching local-mutex.
  • README: fixed stale curlewlabs-com/local-cache/save@v2 reference in the Limitations section, cleaned up ambiguous pre-v3 wording in the "Upgrading from v1" section, and rewrote the Releasing section to match AGENTS.md.

Upgrade

Callers tracking @v3 stay on @v3 and get this change automatically. No code-level change vs v3.0.1.

v3.0.1

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 16 Apr 23:16

Summary

  • Restore-target safety guard. cache-restore.sh now refuses up-front (exit 2) if the caller-provided path is whitespace-only, non-absolute, exactly / / /. / /.., or equal to / an ancestor of \$HOME, \$RUNNER_WORKSPACE, or \$GITHUB_WORKSPACE. The check runs before any filesystem side effect (including --check mode), so a misconfigured workflow can no longer wipe the runner through the unconditional rm -rf on a stale-marker re-sync.
  • Dependency pin bump. curlewlabs-com/local-mutex is now pinned to @v2.0.1. v2.0.1 hashes the name input with SHA-256 unconditionally, so long or special-character cache keys always map to distinct lockfiles (previous versions could collapse keys sharing a 200-char prefix into the same lock).

Behavior for safe callers

  • No interface change. Inputs (path, key, restore-keys, cache-dir) and outputs (cache-hit, cache-matched-key) are unchanged.
  • Existing workflows passing legitimate absolute paths (/tmp/..., runner.tool_cache, etc.) see the same cache-hit/miss behavior as before.

Breaking-ish behavior for misconfigured callers

  • Workflows that were relying on path: expanding to the empty string, a relative path, or $HOME will now fail loudly at Phase 1 with exit 2 instead of silently wiping a directory. This is a bug in the calling workflow, not a regression in local-cache — but if you were depending on the old silent behavior, you'll see new CI failures after upgrading.

Upgrade

Callers tracking @v3 receive this automatically. Callers pinned to @v3.0.0 can move to @v3.0.1.

v3.0.0

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 13 Apr 17:58

First v3 release. Key changes from v2:

  • Collision-safe key encoding: cache keys are SHA-256 hashed into fixed-length directory names. Distinct keys like a/b and a:b no longer collide.
  • Long key support: directory names are always 66 characters regardless of key length.
  • Portability: CI runs on both Linux and macOS; GNU-only find flags removed.
  • Shared helpers: encoding logic extracted to lib/cache-common.sh.

Existing v2 and v1 cache entries are read transparently — no cache invalidation needed on upgrade. Just change @v2 to @v3 in your workflow files.

v2.1.0

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 09 Apr 23:18

What's new

Two-phase restore for steady-state optimization. The restore step now runs in two phases: Phase 1 checks the marker in parallel with no locking — if the target is already current, the restore finishes immediately. If not, Phase 2 acquires a per-key lock (shared with the save step via local-mutex) and performs the full rsync. Steady-state restores never contend on the lock.

LOCAL_CACHE_HIT and LOCAL_CACHE_MATCHED_KEY environment variables. The restore step now exports these to $GITHUB_ENV as a convenience for downstream steps that can't easily reference action outputs.

Output propagation fix. Phase 2 outputs (cache-hit, cache-matched-key) are now correctly propagated through the local-mutex composite action boundary via the new output-file passthrough in local-mutex v1.1.0.

Requires local-mutex@v1 ≥ v1.1.0 (automatic if tracking @v1).

v2.0.5

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 09 Apr 05:26

Critical comment-accuracy and test-strength fix. Previous comments at the post-acquire re-check claimed POSIX mv would refuse to rename onto an existing directory; this is wrong. POSIX mv src dest where dest is a directory NESTS src as dest/basename(src). The re-check is still load-bearing and correct, but for the right reason (preventing nested staging-dir corruption, not preventing a clean mv failure). The Sequential idempotent save test now also asserts no nested staging dir exists, verified locally to catch a removed-guard regression. Plus several smaller fixes: cache-matched-key assertion on sanitized exact hit, dot-key test motivation precision, README purge command now sweeps .tmp-* orphans, .gitignore cleanup.

v2.0.4

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 09 Apr 05:07

Round-3 audit follow-ups and local-mutex pin bump to @v1.0.4 (post-convergence; includes macOS UTF-8 locale fix). Comment accuracy: marker format header now correct for both exact and prefix hits; post-acquire re-check rationale now consistent across file. Test coverage: save-side dot-key rejection now exercised. Documentation precision: first-prefix-wins fallback semantics, accumulation behavior, SIGKILL orphan caveat, save action.yml cache-dir constraint.

v2.0.3

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 09 Apr 04:17

Audit follow-ups and local-mutex pin bump. No user-visible behavior changes on the happy path.

Changes

  • Pin hygiene. actions/checkout@v6 pinned to @v6.0.2 in all three CI jobs. Repo policy is hard-pinning on every ecosystem.
  • Save excludes restore marker. lib/cache-save.sh now passes --exclude=.local-cache-restore to rsync when copying the source into the new entry. On the canonical restore -> install -> save pattern, a prefix-hit restore previously left a stale marker file inside the new on-disk entry. Harmless at runtime but pollutes cache entries with stale metadata.
  • Prefix marker-skip is now covered by CI. Existing tests exercised exact-hit-skip and prefix-match-first-time but not prefix-match-second-time-skip (the is_exact="false" branch in is_current). New CI steps cover both the marker-skip and the save-exclude behaviors.
  • Constant-time marker-skip restored. lib/cache-restore.sh previously ran find ${entries_dir}/ | wc -l unconditionally to populate a ::debug:: log line, contradicting the README's constant-time claim on the happy path. The call is now gated behind RUNNER_DEBUG=1.
  • MARKER_VERSION constant. The inline v2: literal in lib/cache-restore.sh is now a single constant referenced in both is_current and the marker write. .github/workflows/ci.yml keeps its assertion literals with a comment pointing at the canonical source.
  • Marketplace name symmetry. save/action.yml renamed to Runner Local Cache (Save) to match action.yml's Runner Local Cache.
  • README polish. rm command now uses entries/* in both examples (matching semantics). Marker-match wording clarified for the prefix-hit path.
  • curlewlabs-com/local-mutex@v1.0.0 -> @v1.0.1. The sister action just shipped a patch release; local-cache consumes the latest.

Pinned users on @v2 pick this up automatically. Users pinned to @v2.0.2 can bump to @v2.0.3.

v2.0.2

Choose a tag to compare

@jeffwall-curlewlabs jeffwall-curlewlabs released this 09 Apr 03:58

Audit follow-ups: test clarity and documentation precision. No behavior changes. Renames a misleading CI test name (sequential save idempotency, not parallel mutex contention), adds inline comment to load-bearing post-acquire re-check in cache-save.sh, and tightens README wording about restore semantics.