Skip to content

Evict corrupted gitignore.in cache entries instead of trusting them forever - #175

Closed
kitsuyui wants to merge 1 commit into
mainfrom
fix/audit-cache-corrupted-archive-persists-unverified-001
Closed

kitsuyui wants to merge 1 commit into
mainfrom
fix/audit-cache-corrupted-archive-persists-unverified-001

Conversation

@kitsuyui

@kitsuyui kitsuyui commented Sep 8, 2026

Copy link
Copy Markdown
Member

Why

action.yml caches the gitignore.in binary with actions/cache, keyed only by
{os, arch, gitignore-version}. actions/cache never overwrites an existing key, so once a
corrupted or truncated archive is written under a key (e.g. an interrupted upload from a
cancelled earlier run), that key can never be replaced: every later run restores the same bad
bytes. For the bundled version, scripts/install-gitignore-in.sh already re-verifies the
cached archive's SHA-256 and falls back to a fresh download on mismatch, but the corrected
archive had no way back into the cache, so every future run kept re-downloading and
re-detecting the same stale corruption instead of converging on a good, cached state.

What changed

  • action.yml: compute the actions/cache key once in a dedicated step and reuse it both for
    the cache key: and as an env var (GITIGNORE_IN_CACHE_KEY) passed to the install script, so
    the two stay in sync. Also pass GH_TOKEN: ${{ github.token }} to the install step.
  • scripts/install-gitignore-in.sh: when the cached archive fails its SHA-256 check, evict that
    cache entry with gh cache delete "${cache_key}" before falling back to the fresh, verified
    download, so the corrected archive can be saved back under the same key at the end of the run.
    Eviction is best-effort — it needs the actions: write permission on the token; if that's
    missing, it logs a ::warning:: and behavior degrades to the previous
    always-re-download-on-mismatch behavior (no regression, no new failure mode).
  • scripts/test-install-gitignore-in.sh: the shasum stub can now be told to fail on its first
    invocation only (SHASUM_FAIL_ONCE=true), and a gh stub records calls and can simulate a
    failed eviction (STUB_GH_CACHE_DELETE_EXIT=1). Two new tests cover: (1) a corrupted cache hit
    triggers gh cache delete with the right key and a fresh, verified install still succeeds, and
    (2) when eviction itself fails, the action still installs correctly and only logs a warning.
  • README.md: document the cache-eviction behavior and the optional actions: write permission
    it needs.

The intentionally-unverified custom-gitignore-version path
(allow-unverified-gitignore-version: true) is unchanged — that is documented, opt-in behavior,
not the bug this fixes.

Verification

  • scripts/test-install-gitignore-in.sh passes, including the two new tests.
  • shellcheck on scripts/*.sh and on the extracted action.yml run blocks passes.
  • shfmt -d scripts/*.sh reports no diff.

…orever

The gitignore.in binary cache is keyed only by os/arch/version, and
actions/cache never overwrites an existing key. So once a corrupted or
truncated archive is written under a key (e.g. from an interrupted
upload in a cancelled run), that key can never be replaced: every later
run restores the same bad bytes. For the bundled version, a checksum
mismatch was already detected and triggered a fresh download for that
run, but the corrected archive had no way back into the cache, so every
future run kept re-downloading and re-detecting the same stale
corruption instead of converging on a good, cached state.

Compute the cache key once and pass it to install-gitignore-in.sh. When
the cached archive fails its SHA-256 check, evict that cache entry with
`gh cache delete` before falling back to a fresh, verified download, so
the corrected archive can be saved back under the same key at the end
of the run. Eviction is best-effort: it needs the `actions: write`
permission, and its absence only degrades to the previous
always-re-download behavior (with a warning) rather than failing the
run.
@kitsuyui kitsuyui closed this Sep 21, 2026
@kitsuyui
kitsuyui deleted the fix/audit-cache-corrupted-archive-persists-unverified-001 branch September 21, 2026 07:02
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