Contributing to Java Version Manager for Windows
🏠 Overview • 📦 Installation • 📖 Usage • 🏗️ Architecture • 🏢 Enterprise • 🔒 Locking • 🌐 Networking • 🐚 Shells • 🎯 Threat Matrix • ❓ FAQ • ⚖️ SDKMAN! Comparison • 📜 Changelog • 🛡️ Security • 🤝 Contributing • 💬 Support
First off, thank you for considering contributing! It’s developers like you that keep this tool fast, secure, and rock-solid for the Windows engineering community.
🛠️ Local Development & Sandbox Testing
Because jvm.bat actively modifies system and user environment variables (PATH, JAVA_HOME), testing changes directly in your primary environment can disrupt your local development workflow. Follow these sandbox testing practices:
1. Isolated Execution (Local Checkout vs. Global PATH)
When testing local changes in your cloned repository, invoke the script directly from your working directory rather than relying on the installed command:
# In CMD or PowerShell, run the local working copy directly:
.\jvm.bat list
.\jvm.bat current
.\jvm.bat which
.\jvm.bat 21 --session
[!NOTE] Remember: If you already have JVM installed and present in your system
PATH, simply typingjvmwill invoke the globally installed executable rather than your local working copy. When developing and testing locally, always prefix the command with.\(e.g..\jvm.bat listor.\jvm.bat 21 --session). PowerShell argument tab-completion natively supports all three invocation styles:jvm <Tab>,jvm.bat <Tab>, and.\jvm.bat <Tab>! Once installed intoPATH, standard users runjvmwithout prefixes from any directory.
2. Testing Session Switching (Zero System Impact)
Always use the --session flag during manual CLI testing. This mutates only the memory of the active subshell process and leaves your global Windows Registry and User environment untouched:
# CMD subshell verification:
cmd.exe /c ".\jvm.bat 21 --session && java -version"
[!TIP] In PowerShell, running
.\jvm.bat 21 --sessionspawns a transient childcmd.exeprocess, so session environment mutations do not persist into the parent PowerShell process. The globaljvmcommand in PowerShell persists session variables because it is wrapped by the PowerShell$PROFILEhook function (function jvm). When developing locally in PowerShell, use thecmd.exe /cpattern above to test session switching.
3. Dedicated Sandbox Testing
To test directory junction creation and candidate downloads in total isolation, redirect the storage root temporarily before launching jvm.bat:
set "LOCALAPPDATA=%TEMP%\JVM_Sandbox"
.\jvm.bat list
🧪 Automated Test Suite Execution
All contributions are subject to two automated test suites before being merged into main:
1. Security, Error Management & Adversarial Test Suite (tests/Test-JvmSecurity.ps1)
The repository includes an exhaustive 327-test automated adversarial security test suite across 16 suites covering 41 MITRE CWE classes (including CWE-798) with a verified 10.0 / 10.0 scorecard. Our automated GitHub Actions CI pipeline continuously validates all 327 tests concurrently across both native Windows PowerShell 5.1 and modern PowerShell 7+ (Core) to guarantee full cross-version compatibility. This suite validates input sanitization, reparse point operations, atomic failure-path rollbacks, handle disposal, and exit code propagation:
# Run using modern PowerShell 7+ (Recommended):
pwsh -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1
# Or run using native Windows PowerShell 5.1:
powershell -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1
# Run with verbose diagnostic outputs and test millisecond durations:
pwsh -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1 -Detailed
# Target a specific test suite or CWE filter:
pwsh -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1 -Suite 1
pwsh -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1 -Filter "CWE-460"
2. Live OS Integration Test Suite (packages\msi\test-msi.ps1)
DiamTek JVM includes a synthetic 21-point integration test suite (packages\msi\test-msi.ps1) used by our CI/CD pipeline to validate real operating system integration (13 installation & system registration checks + 8 uninstallation & residual hygiene checks).
Running the Integration Test Suite
Open PowerShell (Run as Administrator if testing elevated MSI installation) and execute:
# Run the complete test suite against local build artifacts:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1
# Run with interactive Windows Installer UI dialogs visible:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1 -ShowUI
# Keep the test installation for manual inspection post-run:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1 -KeepInstalled
Building Installer Packages Locally
To verify installer packaging changes:
WiX Toolset v4 Standalone MSI
build-msi.ps1 automatically detects the product version and build number directly from jvm.bat:
# Compiles both x64 and arm64 MSIs into packages\msi\:
powershell -ExecutionPolicy Bypass -File packages\msi\build-msi.ps1 -Arch all
Chocolatey Package
build-choco.ps1 automatically detects the version from jvm.bat, synchronizes jvm.nuspec and fallback URLs, and packages .nupkg:
# Updates nuspec and compiles Chocolatey nupkg into packages\choco\:
powershell -ExecutionPolicy Bypass -File packages\choco\build-choco.ps1
📐 Windows Scripting Rules & Pitfalls
The core jvm.bat engine is over 500 KB of mathematically optimized Windows Batch script. When contributing code, you must adhere to these battle-tested rules:
1. Strict CRLF Line Ending Enforcement
- The Issue: Windows
cmd.exeparses batch scripts line-by-line using byte offsets. If a batch file is checked out with UNIX (LF) line endings,cmd.exemiscalculates byte offsets when parsing multi-line blocks, corruptingechostatements intoe+cho(the infamous “'cho' is not recognized” bug). - The Rule: Never commit LF-only scripts. Ensure git respects
.gitattributes(*.bat text eol=crlf).
2. Delayed Expansion & Exclamation Mark Safety
- The Issue: When
setlocal enabledelayedexpansionis active,cmd.exeeagerly parses exclamation marks (!) as variable references. A file path containing an exclamation mark (e.g.C:\Projects\Test!App) will have its name destroyed. - The Rule:
- Never reference raw user input or unquoted paths inside delayed expansion blocks without prior sanitization.
- In inline PowerShell strings executed via CMD, never use
!for logical negation. Always use the-notoperator (e.g.Where-Object { -not ($_.Name -eq 'foo') }).
3. Quote Encapsulation Across Subshell Boundaries
- The Issue:
PATHstrings on real-world Windows machines often contain rogue unclosed quotes (e.g.,C:\Program Files\Foo"Bar;C:\Java). Standardfor /f "tokens=*" %%a in (...)loops treat quotes as token delimiters, interpreting path segments as nonexistent files. - The Rule: All variable-passing loops must use double-quote encapsulation:
for /f "tokens=*" %%A in ('""!DYNAMIC_CMD!""') do ( ... )
4. Metacharacter Sanitization for Repository Files
- The Issue: Untrusted project
.java-versionand.sdkmanrcfiles can embed shell redirection operators (&,|,<,>) to execute arbitrary code. - The Rule: All file parsing pipelines must enforce metacharacter rejection:
for /f "usebackq tokens=*" %%v in (`type "%CONFIG_FILE%" 2^>nul ^| findstr /v "[&|<>]"`) do ( ... )
5. The “Zero External Dependencies” Rule
- The Rule:
jvm.batmust run cleanly out-of-the-box on a fresh, clean install of Windows 10/11. - Never add external dependencies (
.dll, standalone.exe,curl.exe,tar.exe,unzip.exe, or external.ps1files). All networking, extraction, and cryptographic hashing must rely solely on native Windows APIs and inline PowerShell bridging.
6. Zero Empty Catch Blocks Enforcement (CWE-390)
- The Issue: Silent exception swallowing via empty
catch {}blocks masks runtime failures, prevents proper fallback/recovery, and violates security audit standards (CWE-390). - The Rule: Empty catch blocks are strictly prohibited across all
.ps1scripts and inline PowerShell snippets injvm.bat. All exception blocks must perform explicit handling or diagnostic logging (e.g.,catch { Write-Verbose $_.Exception.Message }). An automated AST audit validates that the repository contains exactly 0 empty catch clauses.
🔄 Pull Request Workflow
We actively welcome contributions! Follow this workflow for a seamless review:
- Fork the repository on GitHub.
- Create a topic branch from
main:git checkout -b feat/add-candidate-scala # or git checkout -b fix/path-quote-handling - Write Conventional Commits:
feat: add Scala support to Universal Candidate Enginefix: resolve delayed expansion path collision in BYO-JDKdocs: update Intune silent deployment switchestest: add synthetic validation case for ARM64 detection
- Run the Pre-Flight Checklist:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\tests\Test-JvmSecurity.ps1passes 327/327 tests (0failures across all 16 suites and 41 MITRE CWE classes).- Verified zero empty catch blocks across all PowerShell files (
CWE-390). cmd.exe /c "jvm.bat --version"executes cleanly with exit code0.- Verified in standard Command Prompt (
cmd.exe). - Verified in Windows PowerShell (5.1) and PowerShell (7+).
- Verified in Windows Terminal.
- UAC-free Symlink Mode switches without prompts.
- No temporary script files left behind in
%TEMP%or%LOCALAPPDATA%\DiamTek\JVM\temp.
- Open a Pull Request targeting the
mainbranch with a clear description and testing proof.
🤝 Code of Conduct
This project adheres to the Contributor Covenant. By participating, you agree to uphold a welcoming, respectful, and inclusive environment for everyone.
Questions or architecture discussions? Reach out to Alexéy Shishkin on Discord (@thehawk01) or via email (salexey09@gmail.com).