fix: guard workspace umo normalization#9006
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- Consider extracting the "unknown" workspace name to a shared constant and documenting the intended behavior for separator-only UMOs, so that callers and future changes don’t accidentally rely on or diverge from this sentinel value.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider extracting the "unknown" workspace name to a shared constant and documenting the intended behavior for separator-only UMOs, so that callers and future changes don’t accidentally rely on or diverge from this sentinel value.
## Individual Comments
### Comment 1
<location path="tests/unit/test_computer_workspace_util.py" line_range="24-33" />
<code_context>
+ assert computer_util.normalize_umo_for_workspace(" _._ ") == "unknown"
+
+
+def test_workspace_root_for_dot_only_umo_stays_under_workspaces(
+ monkeypatch,
+ tmp_path: Path,
+) -> None:
+ workspaces_root = tmp_path / "workspaces"
+ monkeypatch.setattr(
+ computer_util,
+ "get_astrbot_workspaces_path",
+ lambda: str(workspaces_root),
+ )
+
+ root = computer_util.workspace_root("..")
+
+ assert root == (workspaces_root / "unknown").resolve(strict=False)
+ assert root.is_relative_to(workspaces_root.resolve(strict=False))
</code_context>
<issue_to_address>
**suggestion (testing):** Extend `workspace_root` regression coverage to other unsafe UMO values, not just `".."`.
The existing test validates `workspace_root("..")` correctly. To cover the full set of risky UMO values mentioned in the PR, please add/parameterize tests for other dot-only and separator-only inputs (e.g. ".", "...", " _._ ", and values that normalize to only separators). For each case, assert both the resolved path (e.g. `<workspaces_root>/unknown`) and that it remains within `workspaces_root` to prevent future path traversal regressions.
Suggested implementation:
```python
@pytest.mark.parametrize(
"unsafe_umo",
[
".",
"..",
"...",
" _._ ",
"/",
"//",
" / / ",
],
)
def test_workspace_root_for_unsafe_umo_stays_under_workspaces(
unsafe_umo: str,
monkeypatch,
tmp_path: Path,
) -> None:
workspaces_root = tmp_path / "workspaces"
monkeypatch.setattr(
computer_util,
"get_astrbot_workspaces_path",
lambda: str(workspaces_root),
)
root = computer_util.workspace_root(unsafe_umo)
assert root == (workspaces_root / "unknown").resolve(strict=False)
assert root.is_relative_to(workspaces_root.resolve(strict=False))
```
1. Ensure `pytest` is imported at the top of this test module: `import pytest`.
2. If `normalize_umo_for_workspace`’s behavior for separator-only inputs differs (e.g., not mapping to `"unknown"`), you may want to mirror or adjust the set of `unsafe_umo` values in this parametrization to exactly match the “risky” cases defined in the implementation or elsewhere in the PR.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| def test_workspace_root_for_dot_only_umo_stays_under_workspaces( | ||
| monkeypatch, | ||
| tmp_path: Path, | ||
| ) -> None: | ||
| workspaces_root = tmp_path / "workspaces" | ||
| monkeypatch.setattr( | ||
| computer_util, | ||
| "get_astrbot_workspaces_path", | ||
| lambda: str(workspaces_root), | ||
| ) |
There was a problem hiding this comment.
suggestion (testing): Extend workspace_root regression coverage to other unsafe UMO values, not just "..".
The existing test validates workspace_root("..") correctly. To cover the full set of risky UMO values mentioned in the PR, please add/parameterize tests for other dot-only and separator-only inputs (e.g. ".", "...", " . ", and values that normalize to only separators). For each case, assert both the resolved path (e.g. <workspaces_root>/unknown) and that it remains within workspaces_root to prevent future path traversal regressions.
Suggested implementation:
@pytest.mark.parametrize(
"unsafe_umo",
[
".",
"..",
"...",
" _._ ",
"/",
"//",
" / / ",
],
)
def test_workspace_root_for_unsafe_umo_stays_under_workspaces(
unsafe_umo: str,
monkeypatch,
tmp_path: Path,
) -> None:
workspaces_root = tmp_path / "workspaces"
monkeypatch.setattr(
computer_util,
"get_astrbot_workspaces_path",
lambda: str(workspaces_root),
)
root = computer_util.workspace_root(unsafe_umo)
assert root == (workspaces_root / "unknown").resolve(strict=False)
assert root.is_relative_to(workspaces_root.resolve(strict=False))- Ensure
pytestis imported at the top of this test module:import pytest. - If
normalize_umo_for_workspace’s behavior for separator-only inputs differs (e.g., not mapping to"unknown"), you may want to mirror or adjust the set ofunsafe_umovalues in this parametrization to exactly match the “risky” cases defined in the implementation or elsewhere in the PR.
There was a problem hiding this comment.
Code Review
This pull request introduces a check in normalize_umo_for_workspace to handle strings that only contain separator characters, returning 'unknown' in those cases, and adds corresponding unit tests. The reviewer suggests simplifying the return statement by removing the redundant or "unknown" fallback, as separator-only and empty strings are already handled by the new check.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| normalized = re.sub(r"[^A-Za-z0-9._-]+", "_", umo.strip()) | ||
| if not normalized.strip("._-"): | ||
| return "unknown" | ||
| return normalized or "unknown" |
There was a problem hiding this comment.
The or "unknown" fallback is redundant here because any empty or purely separator-based normalized string is already caught and handled by the if not normalized.strip("._-"): check on line 11. Simplifying this to return normalized improves readability.
| return normalized or "unknown" | |
| return normalized |
Summary
normalize_umo_for_workspace()against dot-only or separator-only valuesworkspace_root("..")stays under the configured workspaces directoryqq:GroupMessage:1000andplatform.user-1Why
Per-session computer workspaces are derived from normalized UMO values. Values such as
.or..previously survived normalization and could resolve to the workspaces directory itself or its parent instead of a per-session child directory.Tests
UV_PROJECT_ENVIRONMENT=/tmp/astrbot-venv-8755 uv run pytest -q tests/unit/test_computer_workspace_util.pyUV_PROJECT_ENVIRONMENT=/tmp/astrbot-venv-8755 uv run pytest -q tests/test_computer_fs_tools.py tests/unit/test_message_tools.pyUV_PROJECT_ENVIRONMENT=/tmp/astrbot-venv-8755 uv run ruff format --check .UV_PROJECT_ENVIRONMENT=/tmp/astrbot-venv-8755 uv run ruff check .Summary by Sourcery
Guard workspace UMO normalization against unsafe dot-only values and ensure workspace roots remain confined under the configured workspaces directory.
Bug Fixes:
Tests: