test(lsp/runtime): fix TDD tag to reference bug issue #10490 and add safe-file scenario

Corrected @tdd_issue_10489 → @tdd_issue_10490 so the tag references the
actual bug issue (path traversal vulnerability) rather than the TDD issue
itself.  Added a positive scenario verifying _read_file can still read
files inside the workspace, as suggested in review.

ISSUES CLOSED: #10489
This commit is contained in:
2026-04-22 23:11:20 +00:00
committed by Forgejo
parent b5110761c2
commit e619c1be58
2 changed files with 37 additions and 9 deletions
@@ -1,6 +1,6 @@
"""Step definitions for TDD Issue #10489 — LspRuntime._read_file path containment.
"""Step definitions for TDD Issue #10490 — LspRuntime._read_file path containment.
This test captures bug #10489: ``LspRuntime._read_file()`` in
This test captures bug #10490: ``LspRuntime._read_file()`` in
``src/cleveragents/lsp/runtime.py`` resolves symlinks and ``..`` components
via ``os.path.realpath()`` but does NOT verify that the resolved path is
contained within the workspace directory. An attacker who can control
@@ -8,7 +8,7 @@ contained within the workspace directory. An attacker who can control
the filesystem by supplying a traversal path such as
``<workspace>/../../../etc/passwd``.
The test uses the ``@tdd_expected_fail`` tag until the fix in #10489 is
The test uses the ``@tdd_expected_fail`` tag until the fix in #10490 is
merged. The tag inversion mechanism causes CI to report the scenario as
passed while the bug is still unfixed.
See CONTRIBUTING.md > Bug Fix Workflow > TDD Issue Test Tags.
@@ -97,6 +97,16 @@ def step_lsp_pc_call_read_file_traversal(context: Context) -> None:
context.lsp_pc_error = exc
@when("lsp_pc I call _read_file with the safe file path")
def step_lsp_pc_call_read_file_safe(context: Context) -> None:
"""Call _read_file with a path to the safe file inside the workspace."""
context.lsp_pc_error = None
try:
context.lsp_pc_result = LspRuntime._read_file(context.lsp_pc_safe_file)
except Exception as exc:
context.lsp_pc_error = exc
# ---------------------------------------------------------------------------
# Then steps
# ---------------------------------------------------------------------------
@@ -106,7 +116,7 @@ def step_lsp_pc_call_read_file_traversal(context: Context) -> None:
def step_lsp_pc_lsp_error_raised(context: Context, expected_msg: str) -> None:
"""Assert that _read_file raised LspError with the expected message.
Bug #10489: This assertion FAILS while the bug exists because
Bug #10490: This assertion FAILS while the bug exists because
``_read_file`` does NOT raise ``LspError`` for paths outside the
workspace — it successfully reads the sensitive file instead.
@@ -114,7 +124,7 @@ def step_lsp_pc_lsp_error_raised(context: Context, expected_msg: str) -> None:
so CI reports the scenario as passed until the fix is merged.
"""
assert context.lsp_pc_error is not None, (
"Bug #10489: LspRuntime._read_file() did NOT raise any error when "
"Bug #10490: LspRuntime._read_file() did NOT raise any error when "
f"given a path traversal to a file outside the workspace.\n"
f" Traversal path : {context.lsp_pc_traversal_path!r}\n"
f" Resolved path : {os.path.realpath(context.lsp_pc_traversal_path)!r}\n"
@@ -130,3 +140,16 @@ def step_lsp_pc_lsp_error_raised(context: Context, expected_msg: str) -> None:
f"Expected error message to contain {expected_msg!r}, "
f"but got: {context.lsp_pc_error}"
)
@then("lsp_pc the file content should be returned successfully")
def step_lsp_pc_file_content_returned(context: Context) -> None:
"""Assert that _read_file successfully returned the safe file content."""
assert context.lsp_pc_error is None, (
f"Expected _read_file to succeed for a file inside the workspace, "
f"but got error: {context.lsp_pc_error}"
)
assert context.lsp_pc_result == "# safe content\n", (
f"Expected file content '# safe content\\n', "
f"but got: {context.lsp_pc_result!r}"
)
+9 -4
View File
@@ -1,10 +1,10 @@
@tdd_issue @tdd_issue_10489
Feature: TDD Issue #10489 — LspRuntime._read_file has no workspace path containment check
@tdd_issue @tdd_issue_10490
Feature: TDD Issue #10490 — LspRuntime._read_file has no workspace path containment check
As a security-conscious developer
I want LspRuntime._read_file() to restrict file access to the workspace directory
So that a malicious or misconfigured LLM tool call cannot read arbitrary files
This test captures bug #10489. The ``_read_file`` static method in
This test captures bug #10490. The ``_read_file`` static method in
``src/cleveragents/lsp/runtime.py`` calls ``os.path.realpath()`` to
resolve symlinks and ``..`` components, but does NOT verify that the
resolved path is contained within the workspace directory. An attacker
@@ -19,7 +19,7 @@ Feature: TDD Issue #10489 — LspRuntime._read_file has no workspace path contai
FAILS while the bug exists ``_read_file`` does NOT raise ``LspError``
when given a path that resolves outside the workspace. The tag inversion
mechanism causes CI to report the scenario as passed until the fix lands.
Once the fix for #10489 is merged, the ``@tdd_expected_fail`` tag must be
Once the fix for #10490 is merged, the ``@tdd_expected_fail`` tag must be
removed so the scenario runs normally.
See CONTRIBUTING.md > Bug Fix Workflow > TDD Issue Test Tags.
@@ -30,3 +30,8 @@ Feature: TDD Issue #10489 — LspRuntime._read_file has no workspace path contai
And lsp_pc a sensitive file exists outside the workspace
When lsp_pc I call _read_file with a path that traverses outside the workspace
Then lsp_pc an LspError should be raised with message containing "outside workspace"
Scenario: _read_file can read a file inside the workspace
Given lsp_pc a workspace directory containing a safe file
When lsp_pc I call _read_file with the safe file path
Then lsp_pc the file content should be returned successfully