fix(sdd): upgrade.sh could not deliver the 1.15.0 payload (1.15.1) - #377
Merged
Conversation
The traversal guard in upgrade.sh --apply used plain `realpath --no-symlinks`, which requires every leading path component to already exist. Any MANIFEST entry creating a new directory aborted the run mid-apply, leaving the repository half-upgraded. Reproduced on GNU coreutils — this was never macOS-specific. Concretely: upgrading any pre-1.15.0 install to 1.15.0 died on openspec/changes/_template/specs/, a directory none of them have. The installed base could not reach the release that was meant to repair it. The call now uses `-m` with the `posixpath.normpath` fallback install.sh has carried since 1.14.0, probed once at startup. `..` is still resolved and the prefix check still blocks traversal. The same change covers BSD/macOS, whose realpath does not accept `--no-symlinks` at all — recorded as out of scope in 1.15.0 and pulled forward, because the upgrade tool is what the installed base needs. Adds a blocking C2 upgrade smoke test: install, regress one directory to the pre-1.15.0 shape, then dry-run → approve → --apply, asserting the exact path that used to abort. install.sh had a greenfield gate and a consumer gate; upgrade.sh had none, which is why a defect already fixed in install.sh one release earlier survived here. Also removes the stale [MANUAL ACTION REQUIRED] block from README.md — the repository rename it asked for was completed long ago. Co-Authored-By: Claude Opus 5 (1M context) <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 defect
upgrade.sh --applyguarded against path traversal with plainrealpath --no-symlinks. That form requires every leading path component to already exist, so any MANIFEST entry creating a new directory killed the run — mid-apply, leaving the repository half-upgraded.Reproduced on GNU coreutils. This was never macOS-specific, which is how it was mis-scoped as a deferred portability nit in 1.15.0:
That path is the one 1.15.0 introduced. Upgrading any pre-1.15.0 install to 1.15.0 aborted on it — the installed base could not reach the release written to repair it.
The fix
Use
-mwith theposixpath.normpathfallbackinstall.shhas carried since 1.14.0, probed once at startup...is still resolved; the prefix check still blocks traversal. The identical defect was fixed ininstall.shone release earlier — this just bringsupgrade.shin line.The same change covers BSD/macOS, whose
realpathdoes not accept--no-symlinksat all. Recorded as out of scope in 1.15.0 and pulled forward, because the upgrade tool is precisely what the existing installs need.New gate — the reason this survived
install.shhad a greenfield smoke test (1.14.0) and a consumer smoke test (1.15.0).upgrade.shhad neither, which is the whole reason a defect already fixed elsewhere lived on here.This PR adds a blocking C2 upgrade smoke test: install, regress one directory to the pre-1.15.0 shape, then a full dry-run → approve →
--applycycle, asserting the exact path that used to abort. Exit code alone is not enough — pre-fix, the run applied several files before dying.Verification
Tested in both directions on this host: the scenario fails at that exact path against
upgrade.shat HEAD, and passes with the fix, recreating_template/specs/example-capability/spec.md.verify-release-readiness.sh,verify.sh, andopenspec validate --all --strict(23/23) all green at 1.15.1.Also
Removes the stale
[MANUAL ACTION REQUIRED]block fromREADME.md— the repository rename it asked for was completed long ago.Scope note
The added CI gate goes slightly beyond "fix the bug". I included it because shipping a fix for the one tool nobody ever tested, without a test, repeats the exact mistake. Say the word and I will drop it.
Not fixed here
A failed
--applystill leaves the repository half-upgraded — there is no transaction around the copy loop. Separate concern, recorded, not addressed.🤖 Generated with Claude Code