Skip to content

fix(sdd): upgrade.sh could not deliver the 1.15.0 payload (1.15.1) - #377

Merged
pvilarim merged 1 commit into
masterfrom
claude/fix-upgrade-realpath
Aug 14, 2026
Merged

fix(sdd): upgrade.sh could not deliver the 1.15.0 payload (1.15.1)#377
pvilarim merged 1 commit into
masterfrom
claude/fix-upgrade-realpath

Conversation

@pvilarim

Copy link
Copy Markdown
Owner

The defect

upgrade.sh --apply guarded against path traversal with plain realpath --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:

realpath: /tmp/…/openspec/changes/_template/specs/example-capability/spec.md: No such file or directory

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 -m with the posixpath.normpath fallback install.sh has carried since 1.14.0, probed once at startup. .. is still resolved; the prefix check still blocks traversal. The identical defect was fixed in install.sh one release earlier — this just brings upgrade.sh in line.

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 precisely what the existing installs need.

New gate — the reason this survived

install.sh had a greenfield smoke test (1.14.0) and a consumer smoke test (1.15.0). upgrade.sh had 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 → --apply cycle, 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.sh at HEAD, and passes with the fix, recreating _template/specs/example-capability/spec.md. verify-release-readiness.sh, verify.sh, and openspec validate --all --strict (23/23) all green at 1.15.1.

Also

Removes the stale [MANUAL ACTION REQUIRED] block from README.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 --apply still leaves the repository half-upgraded — there is no transaction around the copy loop. Separate concern, recorded, not addressed.

🤖 Generated with Claude Code

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>
@pvilarim
pvilarim merged commit 4d61c82 into master Aug 14, 2026
1 check passed
@pvilarim
pvilarim deleted the claude/fix-upgrade-realpath branch August 14, 2026 02:56
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