Skip to content

fix(release): bump the version everywhere CI checks, not just pyproject - #8

Merged
ra-co88 merged 2 commits into
mainfrom
hotfix/version-bump-1.0.2b7
Oct 11, 2026
Merged

ra-co88 merged 2 commits into
mainfrom
hotfix/version-bump-1.0.2b7

Conversation

@ra-co88

@ra-co88 ra-co88 commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Hotfix for v1.0.2b7, cut from main per AGENTS.md section 10.

The problem

v1.0.2b7 bumped pyproject.toml, uv.lock and CHANGELOG.md, but not the FnOS packaging manifests, which still said 1.0.2b6. So:

  • tests/unit/test_fnos_docker_persist.py::test_fnos_manifest_version_matches_pyproject failed
  • the Release workflow's Build distributions job died at Run tests (exit 2)
  • Publish to PyPI, Create GitHub Release, Trigger FnOS FPK build and Trigger sync main into develop were all skipped

main was internally inconsistent - pyproject.toml at 1.0.2b7 against manifests at 1.0.2b6 - with the v1.0.2b7 tag sitting on it.

What this changes

The five locations .cursor/skills/publish/SKILL.md lists for a release, beyond the three already done:

  • src/octop/__init__.py - __version__
  • fnos/docker/manifest - version=
  • fnos/native/manifest - version=
  • fnos/docker/app/docker/docker-compose.yaml - image tag
  • README.md / README_CN.md - shields.io version badges

Why the pre-commit hook missed it

The release commit changed only pyproject.toml, uv.lock and CHANGELOG.md. pytest-testmon selects tests by import graph and nothing imports pyproject.toml, so the affected set was empty and the gate ran zero tests.

That is the documented trade-off in the Makefile - "this is local feedback only, so a missed cross-module impact is caught there". Here CI is what caught it. Worth recording: a data-only change to a manifest or lockfile is invisible to testmon by construction, so those files need manual attention on every release.

Verification

  • make all - 4624 passed, 25 skipped, 0 failed, exit 0
  • tests/unit/test_fnos_docker_persist.py + test_self_update.py - 165 passed

Note on the tag

v1.0.2b7 is left where it is, pointing at the commit with the old manifests. Future fork releases should carry a fork-local marker such as +ra.1 so the next upstream merge cannot produce two different releases claiming 1.0.2b7.

Second finding: a Windows-only hole in our own SEC-2 work

Windows CI caught a real defect, so this PR carries two fixes.

file_url_to_abs_path read only urlparse(...).path. That is correct for the canonical file:///C:/…, but Windows CI builds these URLs from Path.as_posix(), which yields the two-slash file://C:/… — where urlparse puts C: in netloc and the path is only /Users/…. The drive was dropped, yielding a drive-relative path (D:/Users/... on the runner).

That broke the SEC-2 guarantee twice:

  • the read test resolved a different path and returned 404 instead of 403
  • the write test wrote the file and returned 200 — containment ran against the mangled path, which sat inside an allowed root

A user-controlled path query parameter could cause a write outside the intended absolute location on Windows, with no 403. This is a defect in our SEC-2 work (d08a6928), not an upstream regression.

Fix reads netloc and, when it is a bare drive letter, prepends it. A UNC host (file://server/share/...) is not a drive letter and takes the existing branch.

The regression test asserts the URL shape, not the filesystem, so it runs on Linux too. Confirmed red on the old code (1 failed, 12 passed) and green on the new (13 passed).

Verification

  • make all — 4625 passed, 25 skipped, 0 failed, exit 0
  • Windows CI green before merge (this is what prompted the second fix)

v1.0.2b7 shipped with pyproject.toml, uv.lock and CHANGELOG bumped, but the
FnOS packaging manifests still said 1.0.2b6, so
tests/unit/test_fnos_docker_persist.py::
test_fnos_manifest_version_matches_pyproject failed and the Release workflow's
"Build distributions" job died at Run tests. Publish to PyPI, Create GitHub
Release, Trigger FnOS FPK build and Trigger sync main into develop were all
skipped, so nothing was published under the Octop name.

main was left internally inconsistent: pyproject 1.0.2b7 against manifests
1.0.2b6, with the v1.0.2b7 tag sitting on it.

Bumps the remaining five locations that .cursor/skills/publish/SKILL.md lists
for a release: src/octop/__init__.py __version__, fnos/docker/manifest,
fnos/native/manifest, the FnOS docker-compose image tag, and the shields.io
version badges in README.md and README_CN.md.

Why the pre-commit hook did not catch this: the release commit changed only
pyproject.toml, uv.lock and CHANGELOG.md. pytest-testmon selects tests by import
graph, and nothing imports pyproject.toml, so the affected set was empty and the
gate ran zero tests. That is the documented trade-off in the Makefile - "this is
local feedback only, so a missed cross-module impact is caught there" - and here
CI is what caught it. Worth remembering that a data-only change to a manifest or
lockfile is invisible to testmon by construction.

Verification: make all = 4624 passed, 25 skipped, 0 failed, exit 0.
tests/unit/test_fnos_docker_persist.py and test_self_update.py: 165 passed.
… netloc

SEC-2, Windows only. Caught by Windows CI, not by anything local.

`file_url_to_abs_path` read only `urlparse(...).path`. For the canonical
three-slash form `file:///C:/…` that is correct — the drive is in the path. But
Windows CI builds these URLs from `Path.as_posix()`, which produces the
two-slash form `file://C:/…`. There `urlparse` puts `C:` in **netloc** and the
path is just `/Users/…`, so the drive was silently dropped.

The result is a drive-relative path. On the GitHub Actions Windows runner the
workdir is on D:, so `/Users/runneradmin/.octop/…` resolved to
`D:/Users/runneradmin/.octop/…` rather than the file the caller named.

That breaks the SEC-2 guarantee in two ways at once:

- `test_file_url_read_outside_allowlist_forbidden` read D:/… , found nothing,
  and returned 404 instead of 403.
- `test_file_url_write_outside_allowlist_forbidden` **wrote the file and
  returned 200**. The containment check ran against the mangled path, which was
  inside an allowed root, so it passed.

A user-controlled `path` query parameter could therefore cause a write outside
the intended absolute location on Windows, with no 403.

The fix reads netloc and, when it is a bare drive letter, prepends it to the
path. A UNC host (`file://server/share/…`) is not a drive letter and is left to
the existing branch.

This is a defect in our own SEC-2 work (d08a692), not an upstream regression.

Regression test is platform-independent so it runs on Linux too — it asserts
the URL shape, not the filesystem. Verified it fails on the old code
(1 failed, 12 passed) and passes on the new (13 passed).

make all: 4625 passed, 25 skipped, 0 failed, exit 0.
@ra-co88
ra-co88 merged commit ffcc383 into main Oct 11, 2026
5 checks passed
@ra-co88
ra-co88 deleted the hotfix/version-bump-1.0.2b7 branch October 11, 2026 05:12
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.

2 participants