Skip to content

Move built-in runtime distribution to Cloudflare R2#72

Merged
angelorc merged 2 commits intomainfrom
t3code/create-public-image-build-system
Mar 11, 2026
Merged

Move built-in runtime distribution to Cloudflare R2#72
angelorc merged 2 commits intomainfrom
t3code/create-public-image-build-system

Conversation

@angelorc
Copy link
Copy Markdown
Owner

@angelorc angelorc commented Mar 11, 2026

Summary

  • move built-in runtime rootfs artifacts to Cloudflare R2 behind artifacts.vmsan.dev
  • add shared runtime build and publish scripts plus a maintainer publish doc
  • switch release installs to manifest-driven runtime downloads while keeping source installs on local builds
  • keep --from-image separate and Docker-backed
  • update install and runtime docs in the existing simple style

Testing

  • bash -n install.sh
  • bash -n scripts/build-runtime-rootfs.sh
  • bash -n scripts/publish-runtimes-to-r2.sh
  • bun run test
  • bun run typecheck
  • remote install test on root@... with VMSAN_DIR=/root/.vmsan-r2test
  • verified docker was absent on the server before and after install
  • verified install.meta and runtime .meta files showed distribution=r2 and recipe_version=3
  • VMSAN_DIR=/root/.vmsan-r2test vmsan doctor
  • VMSAN_DIR=/root/.vmsan-r2test vmsan create --runtime node22 --memory 512 --vcpus 1 --json

Summary by CodeRabbit

  • New Features

    • Prebuilt runtime artifacts (node22, node24, python3.13) distributed with standard releases; manifest-driven runtime resolution with env var overrides and an option to force local builds.
  • Documentation

    • Clarified install behavior: standard releases download prebuilt runtimes; source installs build locally. Docker required only for source/custom image builds.
    • Added maintainer guide for publishing runtimes.
  • Bug Fixes

    • Improved runtime-missing error message to advise installing or refreshing runtime images.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
vmsan Ignored Ignored Preview Mar 11, 2026 11:00am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5f5e76ff-8f29-4594-9b05-45bef124eee9

📥 Commits

Reviewing files that changed from the base of the PR and between 4022acb and 6d990fd.

📒 Files selected for processing (1)
  • .changeset/sour-gifts-dress.md

📝 Walkthrough

Walkthrough

This pull request adds a runtime manifest and distribution system: prebuilt runtime artifacts (node22, node24, python3.13) via manifests and R2, a Dockerfile template and runtime manifest helpers, build/publish scripts for rootfs artifacts, install.sh support for manifest-driven and local builds, and documentation updates clarifying install behavior.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/content/1.getting-started/2.installation.md, docs/content/2.guide/4.docker-images.md, docs/maintainers/r2-runtime-publish.md
Clarified release vs. source install behavior; documented prebuilt runtime artifacts (node22, node24, python3.13), Docker requirements for source builds/--from-image, and R2 publishing workflow and artifact structure.
Docker Runtime Infrastructure
docker/runtimes/Dockerfile.template, docker/runtimes/runtime-manifest.sh
Added a multi-distro Dockerfile template with ubuntu user provisioning and init tweaks; added runtime-manifest.sh exposing runtime names, arches, base image mappings, filenames, arch normalization, and docker platform resolution.
Build & Publish Scripts
scripts/build-runtime-rootfs.sh, scripts/publish-runtimes-to-r2.sh
New scripts to build rootfs artifacts with Buildx, produce compressed ext4 artifacts and metadata, and publish artifacts + release manifests to R2 with verification and optional stable promotion.
Installer Logic
install.sh
Major refactor: supports runtime manifests, remote artifact installs, and conditional local runtime builds; adds helpers for arch mapping, manifest reading, metadata handling, JSON helpers, and separate install/build workflows.
Runtime Docker Manifest Utilities
docker/runtimes/runtime-manifest.sh, docker/runtimes/Dockerfile.template
Centralized runtime metadata and Dockerfile template used by build/publish tooling and installer.
CLI Messages
src/commands/create/args.ts, src/commands/create/environment.ts
Updated runtime argument description and runtime-missing error message to reflect release downloads vs. source local builds.
Changeset
.changeset/sour-gifts-dress.md
New changeset describing runtime distribution change: move built-in runtimes to R2 and manifest-driven release installs.

Sequence Diagram

sequenceDiagram
    actor User
    participant Installer as Install Script
    participant Manifest as Manifest Service
    participant R2 as R2 Storage
    participant Docker as Docker Build
    participant LocalFS as Local Filesystem

    rect rgba(100, 150, 200, 0.5)
    Note over User,LocalFS: Release Install Flow (Prebuilt Artifacts)
    User->>Installer: Run install.sh
    Installer->>Manifest: Fetch runtime manifest
    Manifest-->>Installer: Runtime metadata (url, sha256, bytes, baseImage)
    Installer->>R2: Download runtime artifact
    R2-->>Installer: Rootfs artifact
    Installer->>Installer: Validate checksum & size
    Installer->>LocalFS: Store runtime artifact & metadata
    Installer-->>User: Install complete
    end

    rect rgba(150, 200, 100, 0.5)
    Note over User,LocalFS: Source Install Flow (Local Build)
    User->>Installer: Run install.sh (source mode / FORCE_LOCAL_RUNTIME_BUILD)
    Installer->>Docker: Invoke build-runtime-rootfs.sh
    Docker->>Docker: Build image from Dockerfile.template
    Docker->>Docker: Export filesystem, create ext4, compress
    Docker-->>Installer: Built artifact + metadata.json
    Installer->>Installer: Validate metadata (sha256, bytes)
    Installer->>LocalFS: Store built artifact & metadata
    Installer-->>User: Install complete
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 I stitched the runtimes with care,
Manifests humming through the air,
Prebuilt packages hop on the trail,
Source builds bloom when Docker prevails,
Puff of zstd, a thump—artifact! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Move built-in runtime distribution to Cloudflare R2' clearly and specifically describes the main change: relocating runtime artifacts to R2 storage. It directly aligns with the PR's primary objective and the significant infrastructure changes across install scripts, documentation, and new build/publish automation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch t3code/create-public-image-build-system

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
scripts/publish-runtimes-to-r2.sh (2)

34-42: JSON parsing with regex is fragile.

The json_string_field and json_number_field functions use grep -oP which can fail on:

  • Values containing escaped quotes (\")
  • Multi-line values
  • Nested objects

This works for the current metadata.json structure (simple flat object, no special characters in values), but could break if the metadata format evolves. Consider using jq which is commonly available:

♻️ Suggested alternative using jq
+need_cmd jq

 json_string_field() {
   local key="$1" file="$2"
-  grep -oP "\"$key\"\\s*:\\s*\"\\K[^\"]+" "$file" 2>/dev/null | head -n1 || true
+  jq -r --arg k "$key" '.[$k] // empty' "$file" 2>/dev/null || true
 }

 json_number_field() {
   local key="$1" file="$2"
-  grep -oP "\"$key\"\\s*:\\s*\\K[0-9]+" "$file" 2>/dev/null | head -n1 || true
+  jq -r --arg k "$key" '.[$k] // empty' "$file" 2>/dev/null || true
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/publish-runtimes-to-r2.sh` around lines 34 - 42, The two helper
functions json_string_field and json_number_field use fragile regex-based grep
parsing that breaks on escaped quotes, multiline values, or nested objects;
replace their implementation to parse metadata.json with jq (e.g., use jq -r
".${key}" for strings and jq -r ".${key}" | tonumber for numbers) to reliably
extract fields, and add a graceful fallback to the existing grep approach or
emit an error if jq is not installed; update the functions json_string_field and
json_number_field to call jq on the provided file, handle missing keys by
returning empty string (or nothing) consistent with current behavior, and ensure
any shell-escaping around the key is handled (or require dot-notated keys) so
callers continue to work.

110-112: Consider adding version format validation.

The --version argument is used directly in R2 paths. While unlikely to be malicious in a maintainer script, validating the format (e.g., semver pattern) could prevent accidental issues with special characters in paths.

♻️ Suggested validation
 [ -n "$VERSION" ] || error "--version is required"
+[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]] || error "Invalid version format: $VERSION (expected semver)"
 [ "$CHANNEL" = "stable" ] || error "Only --channel stable is supported in this milestone"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/publish-runtimes-to-r2.sh` around lines 110 - 112, Add a
semantic-version format check for the VERSION variable before it gets used in R2
paths: validate $VERSION with a regex (e.g., optional leading "v" plus
MAJOR.MINOR.PATCH and optional prerelease/build metadata) and call the existing
error helper if it fails; update the validation block around the existing checks
for VERSION, CHANNEL, and PROMOTE_STABLE so that the script rejects malformed
versions early and only proceeds when VERSION matches the semver pattern.
docker/runtimes/runtime-manifest.sh (1)

1-6: Consider documenting the cross-language duplication.

The runtime manifest centralizes metadata for shell scripts, but src/commands/create/types.ts (line 4) and src/commands/create/environment.ts (lines 47-51) independently define the same runtime names and filename mappings in TypeScript. If the manifest is updated, those TypeScript definitions must be updated manually.

Consider adding a comment noting this relationship, or creating a code generation step that produces TypeScript constants from this manifest.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/runtimes/runtime-manifest.sh` around lines 1 - 6, Add a short comment
above the RUNTIME_NAMES and RUNTIME_ARCHES constants in runtime-manifest.sh
explaining these values are duplicated in src/commands/create/types.ts and
src/commands/create/environment.ts (the TypeScript runtime name and filename
mapping constants) and must be kept in sync, and either (preferred) add a small
codegen step to emit TypeScript constants from this manifest (produce types.ts
and environment.ts snippets) or (quick) document the duplication and where to
update the TypeScript files; reference RUNTIME_NAMES/RUNTIME_ARCHES and the
TypeScript files in the comment so future editors know the source of truth and
how to regenerate/update the TS constants.
scripts/build-runtime-rootfs.sh (1)

29-37: Consider handling additional JSON special characters in json_escape.

The function handles backslash, double-quote, newline, carriage return, and tab. However, JSON also requires escaping control characters (U+0000 through U+001F). Characters like form feed (\f) or other control codes in file paths or versions could produce invalid JSON.

For the current use case (runtime names, versions, dates, SHA256 hashes), this is unlikely to be an issue, but consider using jq if available for robust escaping.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build-runtime-rootfs.sh` around lines 29 - 37, The json_escape
function should also escape JSON control characters U+0000 through U+001F (e.g.,
backspace \b, form feed \f and any other non-printable control bytes) to avoid
producing invalid JSON; update json_escape to replace \b and \f with \\b and \\f
and to convert any remaining control bytes (byte values 0x00–0x1F) into \u00NN
Unicode escapes, or, if jq is available, delegate escaping to jq for robustness
(detect jq and use it as a safer fallback when building JSON strings).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.sh`:
- Around line 1064-1069: The install script currently fetches runtimes from
RUNTIME_MANIFEST_URL (stable.json) which can drift from the resolved release
(e.g., LATEST_TAG/npm@latest); update the logic around
RUNTIME_MANIFEST_URL/RUNTIME_MANIFEST_FILE and the install_runtime_from_manifest
loop to instead derive the manifest URL from the resolved release tag (or
download the manifest associated with the resolved release), then validate that
the downloaded manifest.version matches the release tag and abort with a clear
error if it does not; alternatively, if deriving the release-specific manifest
is not possible, fail the install when manifest.version != resolved release
(using the variables/functions RUNTIME_MANIFEST_URL, RUNTIME_MANIFEST_FILE,
LATEST_TAG, BUILTIN_RUNTIMES, and install_runtime_from_manifest) so runtimes are
pinned to the same version as the installed binaries.
- Around line 997-1002: The local-cache skip path for runtime reuse omits CPU
architecture, allowing amd64 builds to be reused on arm64; update the
runtime_metadata_matches checks (the if that currently passes runtime,
distribution local, artifact_version, recipe_version, base_image) to also
compare an arch key (e.g., arch "$arch" or arch "$(uname -m)"), and ensure the
code that writes/persists runtime metadata includes the same arch field so the
cache key records CPU architecture; apply the same change to the other identical
local-skip block that also calls runtime_metadata_matches.
- Around line 163-173: The download() helper currently creates tmp_dest with
mktemp (which defaults to /tmp) causing large downloads to fail on small tmpfs;
change tmp_dest to be created under the target directory by using the target
directory (dirname "$dest") as the temp file location before writing (e.g.,
create a temp file in $(dirname "$dest") or use mktemp -p "$(dirname "$dest")"),
keep the same error handling around curl and rm -f on failure, and then mv the
temp file into "$dest" as the final step—update references to tmp_dest in the
download() function accordingly.

---

Nitpick comments:
In `@docker/runtimes/runtime-manifest.sh`:
- Around line 1-6: Add a short comment above the RUNTIME_NAMES and
RUNTIME_ARCHES constants in runtime-manifest.sh explaining these values are
duplicated in src/commands/create/types.ts and
src/commands/create/environment.ts (the TypeScript runtime name and filename
mapping constants) and must be kept in sync, and either (preferred) add a small
codegen step to emit TypeScript constants from this manifest (produce types.ts
and environment.ts snippets) or (quick) document the duplication and where to
update the TypeScript files; reference RUNTIME_NAMES/RUNTIME_ARCHES and the
TypeScript files in the comment so future editors know the source of truth and
how to regenerate/update the TS constants.

In `@scripts/build-runtime-rootfs.sh`:
- Around line 29-37: The json_escape function should also escape JSON control
characters U+0000 through U+001F (e.g., backspace \b, form feed \f and any other
non-printable control bytes) to avoid producing invalid JSON; update json_escape
to replace \b and \f with \\b and \\f and to convert any remaining control bytes
(byte values 0x00–0x1F) into \u00NN Unicode escapes, or, if jq is available,
delegate escaping to jq for robustness (detect jq and use it as a safer fallback
when building JSON strings).

In `@scripts/publish-runtimes-to-r2.sh`:
- Around line 34-42: The two helper functions json_string_field and
json_number_field use fragile regex-based grep parsing that breaks on escaped
quotes, multiline values, or nested objects; replace their implementation to
parse metadata.json with jq (e.g., use jq -r ".${key}" for strings and jq -r
".${key}" | tonumber for numbers) to reliably extract fields, and add a graceful
fallback to the existing grep approach or emit an error if jq is not installed;
update the functions json_string_field and json_number_field to call jq on the
provided file, handle missing keys by returning empty string (or nothing)
consistent with current behavior, and ensure any shell-escaping around the key
is handled (or require dot-notated keys) so callers continue to work.
- Around line 110-112: Add a semantic-version format check for the VERSION
variable before it gets used in R2 paths: validate $VERSION with a regex (e.g.,
optional leading "v" plus MAJOR.MINOR.PATCH and optional prerelease/build
metadata) and call the existing error helper if it fails; update the validation
block around the existing checks for VERSION, CHANNEL, and PROMOTE_STABLE so
that the script rejects malformed versions early and only proceeds when VERSION
matches the semver pattern.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9689045-9bad-44a4-accb-b31849720560

📥 Commits

Reviewing files that changed from the base of the PR and between 83fd2dd and 4022acb.

📒 Files selected for processing (11)
  • README.md
  • docker/runtimes/Dockerfile.template
  • docker/runtimes/runtime-manifest.sh
  • docs/content/1.getting-started/2.installation.md
  • docs/content/2.guide/4.docker-images.md
  • docs/maintainers/r2-runtime-publish.md
  • install.sh
  • scripts/build-runtime-rootfs.sh
  • scripts/publish-runtimes-to-r2.sh
  • src/commands/create/args.ts
  • src/commands/create/environment.ts

Comment thread install.sh
Comment on lines 163 to 173
download() {
local url="$1" dest="$2"
local tmp_dest
tmp_dest="$(mktemp)"
info "Downloading $(basename "$dest")..."
curl -fsSL -o "$dest" "$url"
if ! curl -fsSL -o "$tmp_dest" "$url"; then
rm -f "$tmp_dest"
error "Failed to download $(basename "$dest") from $url"
fi
mv "$tmp_dest" "$dest"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't stage large artifacts in /tmp.

mktemp defaults to /tmp, so this path now requires /tmp to fit the Ubuntu rootfs and runtime artifacts. On many Linux hosts /tmp is a small tmpfs, which makes installs fail even when $VMSAN_DIR has plenty of space. Stage the temporary file under $(dirname "$dest") instead so the download lives on the target filesystem.

Suggested fix
 download() {
   local url="$1" dest="$2"
-  local tmp_dest
-  tmp_dest="$(mktemp)"
+  local dest_dir tmp_dest
+  dest_dir="$(dirname "$dest")"
+  mkdir -p "$dest_dir"
+  tmp_dest="$(mktemp "$dest_dir/.tmp.$(basename "$dest").XXXXXX")"
   info "Downloading $(basename "$dest")..."
   if ! curl -fsSL -o "$tmp_dest" "$url"; then
     rm -f "$tmp_dest"
     error "Failed to download $(basename "$dest") from $url"
   fi
-  mv "$tmp_dest" "$dest"
+  mv -f "$tmp_dest" "$dest"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
download() {
local url="$1" dest="$2"
local tmp_dest
tmp_dest="$(mktemp)"
info "Downloading $(basename "$dest")..."
curl -fsSL -o "$dest" "$url"
if ! curl -fsSL -o "$tmp_dest" "$url"; then
rm -f "$tmp_dest"
error "Failed to download $(basename "$dest") from $url"
fi
mv "$tmp_dest" "$dest"
}
download() {
local url="$1" dest="$2"
local dest_dir tmp_dest
dest_dir="$(dirname "$dest")"
mkdir -p "$dest_dir"
tmp_dest="$(mktemp "$dest_dir/.tmp.$(basename "$dest").XXXXXX")"
info "Downloading $(basename "$dest")..."
if ! curl -fsSL -o "$tmp_dest" "$url"; then
rm -f "$tmp_dest"
error "Failed to download $(basename "$dest") from $url"
fi
mv -f "$tmp_dest" "$dest"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 163 - 173, The download() helper currently creates
tmp_dest with mktemp (which defaults to /tmp) causing large downloads to fail on
small tmpfs; change tmp_dest to be created under the target directory by using
the target directory (dirname "$dest") as the temp file location before writing
(e.g., create a temp file in $(dirname "$dest") or use mktemp -p "$(dirname
"$dest")"), keep the same error handling around curl and rm -f on failure, and
then mv the temp file into "$dest" as the final step—update references to
tmp_dest in the download() function accordingly.

Comment thread install.sh
Comment on lines +997 to +1002
if [ -f "$dest" ] && runtime_metadata_matches \
"$runtime" \
distribution local \
artifact_version "$artifact_version" \
recipe_version "$expected_recipe_version" \
base_image "$base_image"; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Persist the runtime arch in the local-build cache key.

The local skip path only matches distribution, artifact_version, recipe_version, and base_image. If ~/.vmsan is reused across hosts or restored onto the other CPU architecture, this can incorrectly keep an amd64 runtime on arm64 (or vice versa) because the filename is the same. Record arch in the metadata and compare it before reusing a local build.

Suggested fix
   if [ -f "$dest" ] && runtime_metadata_matches \
     "$runtime" \
     distribution local \
+    arch "$arch" \
     artifact_version "$artifact_version" \
     recipe_version "$expected_recipe_version" \
     base_image "$base_image"; then
     RUNTIME_RECIPE_VERSION_INSTALLED="$expected_recipe_version"
     success "Runtime ${runtime} already built locally"
@@
   write_runtime_metadata \
     "$runtime" \
     distribution local \
+    arch "$arch" \
     artifact_version "$artifact_version" \
     recipe_version "$recipe_version" \
     sha256 "$artifact_sha256" \

Also applies to: 1037-1045

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 997 - 1002, The local-cache skip path for runtime
reuse omits CPU architecture, allowing amd64 builds to be reused on arm64;
update the runtime_metadata_matches checks (the if that currently passes
runtime, distribution local, artifact_version, recipe_version, base_image) to
also compare an arch key (e.g., arch "$arch" or arch "$(uname -m)"), and ensure
the code that writes/persists runtime metadata includes the same arch field so
the cache key records CPU architecture; apply the same change to the other
identical local-skip block that also calls runtime_metadata_matches.

Comment thread install.sh
Comment on lines +1064 to +1069
RUNTIME_MANIFEST_FILE="$(mktemp)"
info "Fetching runtime manifest from $RUNTIME_MANIFEST_URL..."
download "$RUNTIME_MANIFEST_URL" "$RUNTIME_MANIFEST_FILE"
for rt in "${BUILTIN_RUNTIMES[@]}"; do
install_runtime_from_manifest "$rt" "$HOST_RUNTIME_ARCH" "$RUNTIME_MANIFEST_FILE"
done
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pin release runtimes to the same version as the installed binaries.

Release installs resolve LATEST_TAG for the agent/nftables and npm@latest for the CLI, but Line 1065 still pulls runtimes from the moving stable.json channel. The new maintainer flow explicitly allows publishing a release with --promote-stable false, so this can install newer binaries alongside older runtimes during rollout. Either derive the manifest URL from the resolved release or fail if manifest.version does not match the release being installed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 1064 - 1069, The install script currently fetches
runtimes from RUNTIME_MANIFEST_URL (stable.json) which can drift from the
resolved release (e.g., LATEST_TAG/npm@latest); update the logic around
RUNTIME_MANIFEST_URL/RUNTIME_MANIFEST_FILE and the install_runtime_from_manifest
loop to instead derive the manifest URL from the resolved release tag (or
download the manifest associated with the resolved release), then validate that
the downloaded manifest.version matches the release tag and abort with a clear
error if it does not; alternatively, if deriving the release-specific manifest
is not possible, fail the install when manifest.version != resolved release
(using the variables/functions RUNTIME_MANIFEST_URL, RUNTIME_MANIFEST_FILE,
LATEST_TAG, BUILTIN_RUNTIMES, and install_runtime_from_manifest) so runtimes are
pinned to the same version as the installed binaries.

@angelorc angelorc merged commit 204b06e into main Mar 11, 2026
3 of 4 checks passed
@github-actions github-actions Bot mentioned this pull request Mar 11, 2026
@angelorc angelorc deleted the t3code/create-public-image-build-system branch March 14, 2026 10:42
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