From b00218e5c5758e71645b5fb91ecc07acc1f028b7 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Mon, 22 Jun 2026 12:03:06 +0200 Subject: [PATCH] test(phase-12.1): repair live browse validation guard --- backend/tests/test_nextcloud_live.py | 47 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/backend/tests/test_nextcloud_live.py b/backend/tests/test_nextcloud_live.py index 0169a31..fbfccd9 100644 --- a/backend/tests/test_nextcloud_live.py +++ b/backend/tests/test_nextcloud_live.py @@ -27,6 +27,7 @@ import logging import os import re import uuid as _uuid +from contextlib import ExitStack from typing import Optional from unittest.mock import patch, MagicMock @@ -199,21 +200,43 @@ async def test_nextcloud_adapter_read_only_root_metadata(capfd): code = _stable_error_code(exc) pytest.skip(f"Adapter construction failed [{code}].") - # Assert no byte or mutation methods are accessible on the adapter - for method_name in ("get_object", "put_object", "delete_object", - "upload_to", "download_from", "copy", "move", - "create_folder", "rename"): - assert not callable(getattr(type(adapter), method_name, None)), ( - f"T-12.1-17: adapter exposes mutation method {method_name!r}" + # Later phases may legitimately add byte and mutation capabilities to the + # adapter. Phase 12.1's invariant is behavioral: metadata browsing must not + # invoke any of them. Guard both the adapter boundary and its WebDAV client + # so an accidental call fails before network dispatch (T-12.1-17). + forbidden_adapter_methods = ("get_object", "put_object", "delete_object") + forbidden_client_methods = ("download_from", "upload_to", "mkdir", "clean") + guards = [ + patch.object( + adapter, + method_name, + side_effect=AssertionError( + f"T-12.1-17: list_folder called forbidden adapter method {method_name!r}" + ), ) + for method_name in forbidden_adapter_methods + ] + guards.extend( + patch.object( + adapter._client, + method_name, + side_effect=AssertionError( + f"T-12.1-17: list_folder called forbidden WebDAV method {method_name!r}" + ), + ) + for method_name in forbidden_client_methods + ) try: - listing = await adapter.list_folder( - connection_id=connection_id, - user_id=user_id, - parent_ref=None, - page_token=None, - ) + with ExitStack() as stack: + for guard in guards: + stack.enter_context(guard) + listing = await adapter.list_folder( + connection_id=connection_id, + user_id=user_id, + parent_ref=None, + page_token=None, + ) except Exception as exc: code = _stable_error_code(exc) pytest.fail(