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:
@@ -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}"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user