fix: include runner image in cache key to prevent cross-provider collisions

The cache key included only os and arch (`mise-v1-macos-arm64-<hash>`),
so any repo running CI on multiple runner providers with the same
os/arch — github-hosted, namespace.so, BuildJet, self-hosted M-series
macs — would clobber each other's caches. The first run on a new
provider would restore tool installs built for the previous provider's
image, leading to "does not have an executable named X" errors or
SIGILL crashes on cached binaries built against a different glibc.

Append the GitHub Actions hosted-runner ImageOS env var (e.g.
"macos15", "ubuntu24") to the cache key's platform segment. Other
runners pool under "self-hosted"; users running multiple self-hosted
profiles can scope further with cache_key_prefix.

Implementation note: `getTarget()` is also used to construct the mise
binary download URL (must match the release-asset filename, e.g.
`mise-v2026.4.0-macos-arm64.tar.gz`). Adding the image suffix there
would 404 the download. So `getTarget()` keeps its current shape and
a new `getRunnerImageId()` helper composes the image discriminator
into the cache-key platform segment only.

This is a one-time cache miss for existing users; the cache rebuilds
on the next run and stays scoped per-image after that.
This commit is contained in:
jdx 2026-04-30 09:07:02 -05:00
parent ac8a6414ec
commit ef1bd0e351
No known key found for this signature in database
GPG key ID: 584DADE86724B407
4 changed files with 29 additions and 13 deletions

View file

@ -483,11 +483,7 @@ async function saveCache(cacheKey: string): Promise<void> {
}
async function getTarget(): Promise<string> {
let { arch } = process
// quick overwrite to abide by release format
if (arch === 'arm') arch = 'armv7' as NodeJS.Architecture
const arch = process.arch === 'arm' ? 'armv7' : process.arch
switch (process.platform) {
case 'darwin':
return `macos-${arch}`
@ -500,13 +496,25 @@ async function getTarget(): Promise<string> {
}
}
/**
* Identifies the runner image so cached binaries from one provider
* (github-hosted, namespace.so, BuildJet, self-hosted) aren't restored
* onto another provider's image where their compiled-in paths and libc
* versions don't match. GitHub-hosted images export `ImageOS`
* (e.g. "macos15", "ubuntu24"); other runners leave it unset and pool
* under "self-hosted".
*/
function getRunnerImageId(): string {
return process.env.ImageOS || 'self-hosted'
}
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-v1'
const miseEnv = process.env.MISE_ENV?.replace(/,/g, '-')
const platform = await getTarget()
const platform = `${await getTarget()}-${getRunnerImageId()}`
// Calculate file hash
const fileHash = await glob.hashFiles(MISE_CONFIG_FILE_PATTERNS.join('\n'))