Skip to content

fix: select runner image by exact alias match (#86) - #89

Closed
jchak7 wants to merge 3 commits into
WarpBuilds:mainfrom
jchak7:fix-exact-alias-match
Closed

jchak7 wants to merge 3 commits into
WarpBuilds:mainfrom
jchak7:fix-exact-alias-match

Conversation

@jchak7

@jchak7 jchak7 commented Sep 1, 2026

Copy link
Copy Markdown

Problem

Snapshotter.saveSnapshot looks up an existing snapshot by alias and then unconditionally uses the first element of the response:

if ((images.runner_images?.length ?? 0) > 0) {
  runnerImageID = images.runner_images?.[0].id || ''
  const existingArch = images.runner_images?.[0].arch
  const existingOs   = images.runner_images?.[0].os
  versionID = images.runner_images?.[0].warpbuild_snapshot_image?.version_id ?? 0

listRunnerImages returns a list, and the code never checks that any element of it actually is the requested alias — it only checks that the list is non-empty. That is only safe if the endpoint is guaranteed to return exact matches only, in a guaranteed order. Neither is expressed anywhere in this repo, and #86 reports the case where it does not hold: a query for my-image also comes back with siblings such as my-image-arm64.

Two concrete failure modes when that happens:

  1. Wrong image updated — the action snapshots onto a sibling alias, so the alias the user actually asked for silently never gets a new version.
  2. Spurious arch/os failure — if the element that lands at [0] was built for a different architecture, the check immediately below throws ... isn't supported ... even though the requested alias is perfectly valid. Same workflow, same inputs, different outcome depending on response ordering.

Fix

Select the image whose alias is exactly the requested one, rather than trusting position:

const existingImage = images.runner_images?.find(
  image => image.alias === opts.runnerImageAlias
)

if (existingImage) {
  ...
}

This is correct regardless of what the endpoint's matching semantics turn out to be: if it only ever returns exact matches the behaviour is unchanged, and if it returns anything broader the right element is now picked deterministically.

When no exact match exists the code falls through to the create path, which is the correct behaviour for a genuinely new alias — previously a partial-match sibling would have hijacked it into the update path.

Type-safe against the existing model: alias?: string and id: string are both already present on the runner image type, so no type or API changes are needed.

Testing

  • npx tsc --noEmit — clean
  • npx jest — 1/1 passing
  • npx prettier --check — conformant
  • npm run package — dist/ rebuilt and committed so check-dist passes; the compiled bundle contains the find(...) selection and no longer contains runner_images?.[0]

Happy to add a unit test covering the sibling-alias case if you'd like one in the same PR.

Fixes #86

jchak7 added 3 commits October 2, 2026 17:57
saveSnapshot filtered runner images by alias and then unconditionally used
runner_images[0]. The list endpoint can return aliases that merely contain the
requested one -- querying 'my-image' also matches 'my-image-arm64' -- and the
ordering of those results is not guaranteed, so which alias 'wins' varied from
run to run.

That produced two failure modes: the action could update the wrong snapshot
alias, or throw a spurious "isn't supported" arch/os mismatch after picking a
sibling image built for a different architecture.

Select the image whose alias is exactly equal to the requested alias instead of
trusting the first element. When no exact match exists we now fall through to
the create path, which is the correct behaviour for a genuinely new alias.

Fixes WarpBuilds#86
@jchak7
jchak7 force-pushed the fix-exact-alias-match branch from 5cd0122 to 8457870 Compare October 2, 2026 12:29
@jchak7

jchak7 commented Oct 2, 2026

Copy link
Copy Markdown
Author

Rebased on main after #93 landed and rebuilt dist/ against the updated dependencies — merge conflicts cleared, diff is now just the find() selection in snapshotter.ts plus the corresponding bundle change. tsc --noEmit, jest and prettier --check on the touched files are all clean locally. The four workflow runs just need a maintainer approval to execute. Still happy to add a sibling-alias unit test if you'd like one here. cc @janakiram7755

@janakiram7755

Copy link
Copy Markdown
Member

Hi @jchak7 , we have fixed this on the server side a while ago. The alias filter on GET /runner-images now matches exactly, and aliases are unique per organization, so the list returns at most one image for a given alias. With that in place, this change doesn't alter behaviour today, so we're closing this PR.
Thanks.

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.

Snapshot save flakes/fails CI when one alias is a prefix of another (exact-match not enforced)

2 participants