diff --git a/nextcloud_mcp_server/client/__init__.py b/nextcloud_mcp_server/client/__init__.py index c25df187..6891e47d 100644 --- a/nextcloud_mcp_server/client/__init__.py +++ b/nextcloud_mcp_server/client/__init__.py @@ -225,7 +225,7 @@ class NextcloudClient: # cycle on an empty ``data``. Tolerate a missing/empty meta (our own # mocks, and any envelope that omits it). status = (ocs.get("meta") or {}).get("status") - if status not in ("ok", None, ""): + if status and status != "ok": # falsy (missing/None/"") tolerated raise ValueError(f"OCS navigation returned status={status!r}") entries = ocs.get("data") or [] enabled: set[str] = set() diff --git a/tests/unit/vector/test_scanner_app_gating.py b/tests/unit/vector/test_scanner_app_gating.py index ddca0e11..6d2da6ad 100644 --- a/tests/unit/vector/test_scanner_app_gating.py +++ b/tests/unit/vector/test_scanner_app_gating.py @@ -48,6 +48,19 @@ async def test_returns_none_when_detection_raises(caplog): assert "scanning all apps" in caplog.text +async def test_value_error_from_ocs_failure_returns_none(): + """A ValueError (e.g. OCS meta.status=='failure' from get_enabled_apps) + routes through the scan-all fallback like any other exception.""" + nc_client = AsyncMock() + nc_client.get_enabled_apps = AsyncMock( + side_effect=ValueError("OCS navigation returned status='failure'") + ) + + result = await _get_enabled_apps_or_none(nc_client, "alice", scan_id=1234) + + assert result is None + + def test_none_set_enables_every_app(): """A None set means detection failed, so every app must be scanned.""" assert _app_enabled("news", None) is True