Java provisioning (slice 2): install a Temurin JRE when none fits - #39
Merged
Conversation
When no compatible Java is installed, the args editor's warning now carries an "Install Java N" button that downloads a Temurin (Adoptium) JRE into the app's own dir and pins it as the server's Java -- so a server can run on a machine that has the wrong Java, or none. - shared/javaProvision.ts: pure Adoptium shaping -- adoptiumTarget() maps platform/arch (win32->windows, x64->x64, arm64->aarch64, else decline), adoptiumAssetsUrl() builds the v3 assets endpoint (link + published SHA256 in one response), pickAdoptiumPackage() throws rather than proceed on a half-answer, isZipPackage() gates extraction. Plus the JavaInstallProgress type. - core/archive.ts: extractZipSafe() -- adm-zip behind the same zip-slip guard worlds.ts uses, kept standalone so this can be reverted without touching worlds. - core/javaProvision.ts: installJava() -- fetch assets, verify SHA256 as it streams (net.downloadFile), extract, probe, then move into place with an atomic rename staged on the destination filesystem so an interrupted install never leaves a half-tree for the scanner. _resetJavaCache() after. - IPC java:install + evt:java-install-progress; register handler audits the install (source panel, action java.install) like server.create. - ArgsEditor: the needs-install warning becomes an Install button with live phase/percent; on success it pins javaPath + rescans. EN/TR in lockstep. - MSMS_SMOKE_JAVA section 7 pins the os/arch mapping, URL segments, and that an empty or checksum-less assets response throws instead of downloading blind. Verified against the live Adoptium v3 assets response shape. The end-to-end download/extract is not exercised in this env (network + a large binary) -- the pure shaping and guards are; disclosed in the PR. Closes #36, closes #37 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Self-review of slice 2: installJava throws unsupported-platform / unsupported-package on mac/linux (tar.gz) or an odd arch, but the renderer showed one generic "check your connection and try again" toast -- misleading, since retrying never helps. Distinguish it: on an /unsupported/ error, tell the user auto-install isn't available for their OS and to set a path by hand (args.javaInstallUnsupported, EN+TR). Also renamed the local handler off the window.msms.installJava name it shadowed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
Author
Self code-reviewReviewed for the two things that matter most in a download-and-run feature: integrity and not leaving a mess on failure. Integrity path — holds up
Atomicity — holds up
Found + fixed on-branch (
|
Advisor review caught the important one: runInstall ended with
set('javaPath', ...) which only updates local form state, so the JRE it just
downloaded was NOT saved unless the user then clicked Save -- while the toast
said "now selected for this server". That silently reintroduces the exact
failure this feature exists to fix (the next launch picks the wrong Java again).
Persist it immediately with updateServer(id, { java: { ...server.java, javaPath }})
-- spreading the *saved* server.java so an unrelated unsaved form edit isn't
committed alongside it.
Hardening: stage the download under a fixed name (jre.zip) instead of the
API-supplied package name, so an external string is never a path component.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
Author
Follow-up (advisor review)One more real defect, fixed on-branch (
Re-verified: |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Slice 2 completes auto Java provisioning: when no compatible JRE is installed, the args-editor warning grows an "Install Java N" button that downloads a Temurin (Adoptium) JRE into the app's own directory, verifies it, and pins it as that server's Java. So a server can run on a machine that has the wrong Java — or none at all. Opt-in only; nothing installs on its own.
How
Pure (
src/shared/javaProvision.ts) — the parts easy to get wrong, kept testable:adoptiumTarget(platform, arch)maps Node's names to Adoptium's (win32→windows,x64→x64,arm64→aarch64), and returnsnullfor anything we can't name — the UI then declines rather than fetch a guess.adoptiumAssetsUrl(major, target)builds the v3 assets endpoint, which returns the download link and the vendor's published SHA256 in one response.pickAdoptiumPackage(assets)throws on an empty or field-missing response — an unverifiable download is worse than none.isZipPackage(name)gates extraction to.zip(Windows) this slice.Main:
core/archive.ts—extractZipSafe():adm-zipbehind the same zip-slip guardworlds.tsuses, kept as its own module so this feature reverts without touching worlds.core/javaProvision.ts—installJava(): fetch assets → verify SHA256 as it streams (net.downloadFiledeletes + throws on mismatch) → extract → probe that it actually runs → move into place with an atomic rename staged on the destination filesystem (no cross-deviceEXDEV, no half-tree if interrupted) →_resetJavaCache(). Installs land in<baseDir>/java/temurin-<major>/, whichjavaScanalready searches, so the new JRE also appears in the picker.java:install+evt:java-install-progress; the handler audits the install (source: panel,action: java.install) exactly likeserver.create.UI: the slice-1 needs-install warning becomes an Install button with a live phase/percent line; on success it pins
javaPathand rescans. EN/TR keys in lockstep.Verification
typecheckclean,buildclean.MSMS_SMOKE_JAVAPASS — new section 7 pins: os/arch mapping (incl. unknown OS/arch → decline), the URL segments,.zipvs.tar.gz, and that an empty or checksum-less assets response throws instead of downloading blind.MSMS_SMOKE(spine) PASS — app still boots with the new IPC/preload/handler.Disclosed gaps
.zippackages install. mac/linux Temurin ships.tar.gz; those decline withunsupported-package(tar extraction is a follow-up). The app's primary target is the Windows portable build.javaPathstores an absolute<baseDir>/java/...path; if the portable app is later moved, that path breaks and the server falls back to the picker/auto. Acceptable for now.--installServermay want a full JDK; this installs a JRE (enough to run). Out of scope.Closes #36, closes #37