fix: move file_hash to end of cache key template to prevent prefix matching (#384)

## Summary

Refs #382 (Problem 1).

The default cache key template placed `file_hash` before conditional
segments (`version`, `mise_env`, `install_args_hash`). Because
`@actions/cache` `restoreCache` performs prefix matching on the primary
key, a key without optional trailing segments was always a prefix of a
key with them, causing different workflow configurations to restore each
other's caches unintentionally.

## The bug

Old template:
```
{{cache_key_prefix}}-{{platform}}-{{file_hash}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}
```

Example: Workflow A (no `install_args`) produces key
`mise-v0-linux-x64-<hash>`, which is a prefix of Workflow B's key
`mise-v0-linux-x64-<hash>-<args_hash>`. If only B's cache exists, A
restores it via prefix match.

## The fix

Move `file_hash` to the end of the template so it acts as a terminator:
```
{{cache_key_prefix}}-{{platform}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}-{{file_hash}}
```

Since `file_hash` is always present, no valid cache key can be a prefix
of another.

Also bumps `cache_key_prefix` default from `mise-v0` to `mise-v1` (in
both `src/index.ts` and `action.yml`) to intentionally invalidate
existing caches that may have been saved under incorrect prefix-matched
keys.

## Changes

- `src/index.ts` L43: Reorder `DEFAULT_CACHE_KEY_TEMPLATE` — move
`file_hash` to end
- `src/index.ts` L432: Bump fallback `cache_key_prefix` from `mise-v0`
to `mise-v1`
- `action.yml` L46: Bump default `cache_key_prefix` from `mise-v0` to
`mise-v1`
- Rebuilt `dist/`
This commit is contained in:
Kyle Altendorf 2026-02-21 08:58:21 -05:00 committed by GitHub
parent e371f56f61
commit f1c6089fba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 6 additions and 6 deletions

View file

@ -43,7 +43,7 @@ inputs:
description: if false, action will not write to cache
cache_key_prefix:
required: false
default: "mise-v0"
default: "mise-v1"
description: The prefix key to use for the cache, change this to invalidate the cache
cache_key:
required: false

4
dist/index.js generated vendored
View file

@ -80940,7 +80940,7 @@ const MISE_CONFIG_FILE_PATTERNS = [
`**/.tool-versions`
];
// Default cache key template
const DEFAULT_CACHE_KEY_TEMPLATE = '{{cache_key_prefix}}-{{platform}}-{{file_hash}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}';
const DEFAULT_CACHE_KEY_TEMPLATE = '{{cache_key_prefix}}-{{platform}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}-{{#if file_hash}}{{file_hash}}{{else}}no-config{{/if}}';
async function run() {
try {
await setToolVersions();
@ -81271,7 +81271,7 @@ async function processCacheKeyTemplate(template) {
// Get all available variables
const version = core.getInput('version');
const installArgs = core.getInput('install_args');
const cacheKeyPrefix = core.getInput('cache_key_prefix') || 'mise-v0';
const cacheKeyPrefix = core.getInput('cache_key_prefix') || 'mise-v1';
const miseEnv = process.env.MISE_ENV?.replace(/,/g, '-');
const platform = await getTarget();
// Calculate file hash

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View file

@ -40,7 +40,7 @@ const MISE_CONFIG_FILE_PATTERNS = [
// Default cache key template
const DEFAULT_CACHE_KEY_TEMPLATE =
'{{cache_key_prefix}}-{{platform}}-{{file_hash}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}'
'{{cache_key_prefix}}-{{platform}}{{#if version}}-{{version}}{{/if}}{{#if mise_env}}-{{mise_env}}{{/if}}{{#if install_args_hash}}-{{install_args_hash}}{{/if}}-{{#if file_hash}}{{file_hash}}{{else}}no-config{{/if}}'
async function run(): Promise<void> {
try {
@ -429,7 +429,7 @@ async function processCacheKeyTemplate(template: string): Promise<string> {
// Get all available variables
const version = core.getInput('version')
const installArgs = core.getInput('install_args')
const cacheKeyPrefix = core.getInput('cache_key_prefix') || 'mise-v0'
const cacheKeyPrefix = core.getInput('cache_key_prefix') || 'mise-v1'
const miseEnv = process.env.MISE_ENV?.replace(/,/g, '-')
const platform = await getTarget()