fix: move the updater body out of cmd's 8,191 character command line - #7
Merged
Merged
Conversation
update.bat built its whole PowerShell body from caret-continued double-quoted fragments. cmd joins those into one logical line and truncates it at 8,191 characters. The block had reached 17,182, so cmd kept the first 8,191, cut mid-token inside `function Start-HumWatch`, handed PowerShell a script with unclosed braces, and then tried to run the discarded remainder as a command. Every install failed at parse time with exit 9009 and never wrote _update_status.txt. Verified end to end on Windows 11 under real UAC elevation against the built v2.0.1 archive. The body now lives in scripts/update-core.ps1, invoked with -File. The logic is unchanged. update.bat keeps the banner, the fltmc elevation gate, and nothing else. Three related fixes while the file was open: - The invocation is now the last line cmd reads. The release swap replaces update.bat mid-run and cmd resumes a batch file by byte offset, so any following line would be read out of the new file at the old offset. `exit /b` rides the same buffered logical line, and the result banner moved into the PowerShell script. - The elevation block read %errorlevel% and %UPDATE_EXIT% under EnableDelayedExpansion, so both expanded at block-parse time. It propagated correctly only because `exit /b` with no argument preserves the current errorlevel. - A failed update now prints the underlying error and waits, instead of closing the elevated console before the operator can read anything. Tests: the caret-block reconstruction helper is gone, replaced by a bound on every cmd logical line across all four batch entrypoints, plus a shape test pinning update.bat as a launcher. The updater contract tests read both halves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The blocker
update.batbuilt its entire PowerShell body from caret-continued double-quoted fragments. cmd joins those into one logical line and truncates it at 8,191 characters. The block had reached 17,182.cmd kept the first 8,191 and discarded 8,991. The cut landed mid-word inside
function Start-HumWatch:PowerShell got a script with unclosed braces and failed at parse time. cmd then tried to execute the discarded remainder as a command. Exit 9009, no
_update_status.txt, updater completely non-functional on every install.It failed safely (the parse error lands well before
Stop-HumWatch, so nothing was ever mutated) but v2.0.1 could not ship a working one-click updater.The block was 5,193 characters from v0.9.5 through v1.0.1, so no published install is stranded. It outgrew the limit during the v2.0.x hardening work.
The fix
The body moves verbatim to
scripts/update-core.ps1, invoked with-File. No update logic changed.update.batkeeps the banner, thefltmcelevation gate, and nothing else.Three related fixes while the file was open:
update.batmid-run, and cmd resumes a batch file by byte offset, so any following line would be read out of the new file at the old offset.exit /brides the same already-buffered logical line, and the result banner moved into the PowerShell script. Verified that PowerShell keeps executing the parsed original after its own script file is overwritten, so mirroringscripts\mid-transaction is safe.%errorlevel%in the elevation block expanded at block-parse time underEnableDelayedExpansion. Demonstrated on Windows: in that block shape%errorlevel%reads0where!errorlevel!reads the child's real77. It only propagated correctly before becauseexit /bwith an empty argument preserves the current errorlevel.UserInteractiveandIsInputRedirectedso scripted runs never block.Tests
The caret-block reconstruction helper is gone. In its place:
test_batch_entrypoints_stay_under_the_cmd_command_line_limitbounds every cmd logical line across all four batch entrypoints.test_update_batch_is_only_a_launcher_for_the_powershell_corepins the launcher shape, the trailingexit /b, and the absence of%errorlevel%.test_update_core_is_a_real_script_not_a_cmd_command_stringkeeps the body from moving back.Set-HardenedAppAclout of the real script instead of reconstructing it from cmd fragments.The old
#-comment regression test was correct and passing. It reconstructed the joined-Commandsource and never measured it, which is why CI missed a 17KB line.Verification on Windows 11 (26100, PowerShell 5.1)
update-core.ps1parses under Windows PowerShell 5.1update.batthrough cmd (only thefltmcgate stubbed, same byte length, CRLF preserved)update.batunder an admin token, from the built v2.0.1 archive_update_status.txtghpresent (gh branch)ghoff PATH (anonymousInvoke-RestMethodfallback, previously unexercised)1.0.1build-release.ps1withscripts\update-core.ps1added to the required entriesThe clean error in every run is
The named release or its SHA256 manifest is missing, which is correct: the latest published release isv1.0.1and it has no.zip/.sha256assets.Not covered
The UAC self-elevation branch was not re-run end to end here, since the SSH session already holds an admin token so
fltmcsucceeds. That branch was confirmed working on this hardware before this change, theStart-Process -Verb RunAsline is untouched, and the exit-code propagation it depends on is tested in isolation above.A full successful update remains impossible to exercise until v2.0.1 assets exist.
🤖 Generated with Claude Code