Release v0.51.296 — stage-3731 (remote-workspace blocked-root security fix #3731) (#3744)
Some checks failed
Release & Docker / release (push) Has been cancelled

* fix: reject blocked roots for remote workspaces

* test: cover remote blocked root subpaths

* docs(changelog): v0.51.296 security fix + backfill v0.51.295 entries

- v0.51.296: #3731 remote-workspace blocked-root rejection.
- Backfill the v0.51.295 release block (the #3739 model-pick entry + promote the
  #3570 revert out of [Unreleased]) which a stage-rebuild dropped from the prior
  release's CHANGELOG. git-describe versioning makes CHANGELOG-after-tag acceptable.

---------

Co-authored-by: hinotoi-agent <paperlantern.agent@gmail.com>
Co-authored-by: nesquena-hermes <[email protected]>
This commit is contained in:
nesquena-hermes
2026-06-06 13:49:59 -07:00
committed by GitHub
parent 65c4bc9fa2
commit 91a89fb5d5
3 changed files with 23 additions and 0 deletions

View File

@@ -3,6 +3,16 @@
## [Unreleased]
## [v0.51.296] — 2026-06-06 — Release JL (stage-3731 — remote-workspace blocked-root security fix)
### Security
- **Remote-terminal workspace resolution now rejects blocked system roots.** `_remote_terminal_workspace_candidate()` returned early for paths under the configured remote terminal cwd *before* the blocked-root guard ran, so an SSH/remote terminal profile whose target-side cwd was a system directory (e.g. `/etc`) could have that root accepted as a local workspace — after which workspace file helpers (which treat `s.workspace` as a local `Path`) could read local system files. The blocked-root guard now runs for both the candidate and the base path, so registration and trusted-workspace resolution reject these roots consistently. (#3731, @Hinotoi-agent)
## [v0.51.295] — 2026-06-06 — Release JK (stage-3739/3742 — model-pick revert fix + session-status revert)
### Fixed
- **The composer model picker no longer silently reverts your selection on send.** When you explicitly picked a model whose family differed from the active profile's provider (e.g. a `gpt-*` model under an `anthropic`-bound profile), the server's profile-aware resolution (v0.51.290, #3448) rewrote it to the profile default and the dropdown snapped back with no warning. An explicit pick is now honored across both resolution paths (the profile-provider branch and the legacy bare-prefix branch), and if the model genuinely must change (a real provider mismatch) a toast explains it instead of silently swapping. The legitimate stale-session repair path is preserved. (#3739 fixes #3737, @someaka)
### Removed
- **Reverted the manual per-session status labels (Todo / In Progress / Done).** The feature added in v0.51.284 (#3570) stored the chosen status only in browser `localStorage`, keyed by session id, with no server-side backing — so labels silently did not persist across browsers or devices (a user who labeled sessions on one machine saw none of them after switching to a laptop). It also rendered the three statuses as flat top-level entries in the session context menu alongside Copy/Rename/Pin/etc., which crowded the root menu. Removed entirely for now (JS state + cycle logic, context-menu entries, sidebar badge render, CSS, and all locale strings); the feature can be reintroduced later with proper server-side persistence and a less intrusive menu treatment. (reverts #3570)

View File

@@ -93,6 +93,8 @@ def _remote_terminal_workspace_candidate(path: str | Path) -> Path | None:
return None
candidate = Path(raw).expanduser().resolve()
base = Path(cwd).expanduser().resolve()
if _is_blocked_workspace_path(candidate, raw) or _is_blocked_workspace_path(base, cwd):
return None
if candidate == base or _is_within(candidate, base):
return candidate
return None

View File

@@ -55,3 +55,14 @@ def test_remote_terminal_workspace_paths_outside_cwd_still_reject(monkeypatch):
with pytest.raises(ValueError, match="Path does not exist"):
workspace.resolve_trusted_workspace("/Users/other/projects/demo")
@pytest.mark.parametrize("workspace_path", ["/etc", "/etc/ssh"])
def test_remote_terminal_workspace_system_roots_still_reject(monkeypatch, workspace_path):
monkeypatch.setattr(api_config, "get_config", lambda: _remote_config(terminal={"backend": "ssh", "cwd": "/etc"}))
with pytest.raises(ValueError, match="Path points to a system directory"):
workspace.validate_workspace_to_add(workspace_path)
with pytest.raises(ValueError, match="Path points to a system directory"):
workspace.resolve_trusted_workspace(workspace_path)