Skip to content

Workspace-root refusal is logged like an internal error, and never asserted #23

Description

@n1ckyb

What you see

WARNING  intentumdiff.lsp_server.server: intentumdiff/semanticDiff error: URI 'file:///.../evil/old.py'
resolves to WindowsPath('.../evil/old.py') which is outside the workspace root WindowsPath('.../project').
PASSED                                                                   [ 49%]

A WARNING immediately followed by PASSED, which reads like something went wrong and was ignored.

It is correct behaviour

test_uri_outside_root_returns_0 deliberately asks the LSP server to diff a path outside the workspace root. The server refuses — this is a path-traversal guard doing its job — and lsp_server/server.py:202 logs the refusal before returning an error response to the client.

Two things worth fixing

1. The warning is not asserted, and this one is a security control

Nothing checks that the warning is emitted. The test only asserts the return value, so the log line could vanish entirely and the test would still pass.

That matters more here than for an ordinary warning: the audit trail is part of the control. A server that silently refuses a traversal attempt tells an operator nothing. Capture it and assert it:

def test_uri_outside_root_returns_0(caplog):
    with caplog.at_level(logging.WARNING, logger="intentumdiff.lsp_server.server"):
        ...
    assert "outside the workspace root" in caplog.text

That converts noise into coverage, and pins the behaviour rather than merely permitting it.

2. A refused traversal is not the same as an unexpected error

server.py:201-203 catches every Exception and logs it identically:

except Exception as exc:  # noqa: BLE001
    log.warning("intentumdiff/semanticDiff error: %s", exc)

So a deliberate, expected security refusal and a genuine internal fault produce the same line at the same level. An operator cannot tell "someone probed outside the workspace and we blocked it" from "the diff engine threw".

Suggested: give the containment failure its own exception type and log it distinctly — same level is fine, different message, ideally a stable code the client can key on. The point is that the two are different events and should be greppable apart.

Scope

Small, not release-blocking. Filed for the same reason as #21: a run full of unexplained warnings trains everyone to skim past them, which is how 0.0.1 shipped printing 69 errors per invocation while exiting 0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions