Skip to content

Fix download endpoint returning wrong artifact for unmatched platform#47

Merged
shwetank-dev merged 6 commits intomainfrom
issue-34
Mar 17, 2026
Merged

Fix download endpoint returning wrong artifact for unmatched platform#47
shwetank-dev merged 6 commits intomainfrom
issue-34

Conversation

@shwetank-dev
Copy link
Collaborator

Summary

Fixes #28 — the bundle download endpoint (/v1/bundles/@:scope/:package/versions/:version/download) was silently serving a wrong-platform artifact when the requested os/arch didn't match any available artifact. For example, requesting os=linux&arch=arm64 for a bundle that only had darwin-arm64 would return the darwin-arm64 artifact with a 200 instead of a 404.

Root cause

The artifact selection logic defaulted to artifacts[0] and never cleared that default when platform params were provided but didn't match:

let artifact = packageVersion.artifacts[0]; // always set
if (queryOs || queryArch) {
  const match = ...; // if no match found, artifact stays as artifacts[0]
}

Fix: resolveArtifact helper

Replaced the inline logic with a resolveArtifact(artifacts, os?, arch?) function that enforces these rules:

Params provided Artifact state Result
Neither os nor arch any/any exists 200 — returns universal artifact
Neither os nor arch No any/any 404
Only one of os/arch 400 — "both os and arch are required"
Both os and arch Exact match exists 200 — returns matched artifact
Both os and arch No match 404
Invalid enum values 422 — rejected at schema level

Zod schema validation

  • Added BundleDownloadParamsSchema to @nimblebrain/mpak-schemas with enum validation (os: darwin/linux/win32, arch: x64/arm64)
  • Added BundleVersionPathParamsSchema in apps/registry/src/schemas/bundles.ts for path params
  • Replaced inline JSON Schema definitions with toJsonSchema() calls
  • Added Fastify generics to remove manual as type casts

Other changes in this branch

  • Replaced registry-local generated schemas with shared @nimblebrain/mpak-schemas package
  • Added Zod-based type safety to the bundle search route (BundleSearchParamsSchema)
  • Added package seed data (echo with universal artifacts, nationalparks with multi-platform artifacts)
  • Added search validation tests (invalid pagination, enum rejection, defaults, has_more)

Test plan

  • pnpm --filter @nimblebrain/mpak-registry typecheck — passes
  • pnpm --filter @nimblebrain/mpak-registry lint — passes
  • pnpm --filter @nimblebrain/mpak-registry test — 93 tests pass (7 new download tests)
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/nationalparks/versions/latest/download?os=linux&arch=arm64' → 404
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/nationalparks/versions/latest/download?os=foo&arch=bar' → 422
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/nationalparks/versions/latest/download?os=darwin&arch=arm64' → 200
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/echo/versions/latest/download' → 200 (universal)
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/nationalparks/versions/latest/download' → 404 (no universal)
  • Manual: curl 'localhost:3200/v1/bundles/@nimblebraininc/echo/versions/latest/download?os=linux' → 400 (missing arch)

🤖 Generated with Claude Code

shwetank-dev and others added 6 commits March 13, 2026 18:11
Add seed data for two MCPB packages alongside existing skill seeds:
- @nimblebraininc/echo: 9 versions (including prereleases), python server
- @nimblebraininc/nationalparks: 6 versions, node server with user config
Includes manifest helpers, version upserts, and download counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The registry had duplicated schema files in src/schemas/generated/ that
mirrored the shared package. This caused maintenance burden and version
drift. Import directly from @nimblebrain/mpak-schemas instead and delete
the generated copies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hand-written JSON Schema querystring with BundleSearchParamsSchema,
use Fastify generics for type-safe request access, type the response as
BundleSearchResponse, and replace runtime clamping with schema validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Register errorHandler in test setup for 422 parity with production
- Replace clamping test with schema validation rejection tests
- Add tests for defaults, type filter, enum validation, q length,
  limit boundary, and has_more pagination
- Seed artifacts for echo (universal) and nationalparks (multi-platform)
- Create placeholder .mcpb files on disk for local download testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add resolveArtifact helper to enforce platform selection rules:
- Both os and arch required together (400 if only one provided)
- Exact platform match when both specified (404 if no match)
- Universal any/any artifact when no platform params (404 if none)
- Invalid enum values rejected at schema level (422)

Previously the endpoint fell back to artifacts[0] when no match was
found, silently serving a wrong-platform artifact (e.g. darwin-arm64
when linux-arm64 was requested). Fixes #28.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shwetank-dev
Copy link
Collaborator Author

closes #38 #47

@mgoldsborough mgoldsborough added the qa-reviewed QA review completed with no critical issues label Mar 16, 2026
@shwetank-dev shwetank-dev merged commit f5d175d into main Mar 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

qa-reviewed QA review completed with no critical issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API returns 500 when downloading bundle with version=latest and platform params

2 participants