Skip to content

Guard manage_asset search against broad scans#1185

Open
liuzqk wants to merge 1 commit into
CoplayDev:betafrom
liuzqk:fix/manage-asset-search-guard
Open

Guard manage_asset search against broad scans#1185
liuzqk wants to merge 1 commit into
CoplayDev:betafrom
liuzqk:fix/manage-asset-search-guard

Conversation

@liuzqk
Copy link
Copy Markdown

@liuzqk liuzqk commented May 31, 2026

Summary

Fixes #1177.

  • normalize malformed manage_asset(action="search") calls that put the query in path
  • reject empty or date-only search requests before they dispatch to Unity
  • reject invalid Unity folder scopes instead of falling back to a full-project AssetDatabase search
  • apply pagination before GetAssetData so search results do not materialize full asset metadata before slicing
  • add Python integration tests and Unity EditMode coverage for the dangerous search cases

Why

An empty or invalid search scope can call AssetDatabase.FindAssets("") and then process metadata for the entire project. Large Unity projects can stall while GetAssetData runs over every asset.

Validation

  • uv run --extra dev python -m pytest tests/integration/test_manage_asset_search_guard.py tests/integration/test_manage_asset_json_parsing.py -q
  • python -m py_compile Server/src/services/tools/manage_asset.py
  • git diff --check

I also attempted the new Unity EditMode test locally, but this checkout's UnityMCPTests project is pinned to Unity 2021.3.45f2 and the available local editor was 2022.3.62f3, which only triggered package/project upgrade work and did not produce a test result. Those generated changes were discarded.

Summary by CodeRabbit

  • New Features

    • Enhanced search parameter validation with clearer error messaging for invalid inputs.
  • Bug Fixes

    • Invalid folder scopes now return appropriate errors instead of defaulting to full-project search.
  • Performance

    • Search results now apply pagination before fetching asset data, reducing unnecessary processing.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR hardens ManageAsset search by introducing validation at both server and editor levels to prevent malformed requests, normalizes folder-scope detection to correctly interpret search criteria, and optimizes result fetching to defer asset data loading until after pagination applies, avoiding excessive processing when projects contain many assets.

Changes

Search Validation and Performance

Layer / File(s) Summary
Server Input Normalization and Guard
Server/src/services/tools/manage_asset.py
Python server detects folder scopes, normalizes non-folder paths into search patterns, reroutes AssetDatabase-style queries, and validates that either a folder scope or at least one search criterion is provided before dispatching to Unity.
Unity Editor Request Validation and Error Handling
MCPForUnity/Editor/Tools/ManageAsset.cs
C# editor code trims inputs, validates page size and number are positive, rejects requests without valid folder scope or search filters with explicit error responses, and no longer falls back to searching the entire project for invalid paths.
Deferred Asset Data Loading and Pagination
MCPForUnity/Editor/Tools/ManageAsset.cs
Search pipeline collects matching asset paths into an intermediate collection, applies pagination to the path list, and invokes GetAssetData only for the paged subset of results instead of eagerly loading all matching assets.
Server Integration Test Coverage
Server/tests/integration/test_manage_asset_search_guard.py
Python async tests validate that empty searches and date-only searches without scope or filter return error responses, and that valid searches correctly normalize paths and preserve folder scopes when dispatching to Unity.
Unity EditMode Test Coverage and Metadata
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageAssetSearchGuardTests.cs, TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageAssetSearchGuardTests.cs.meta
C# EditMode tests verify that unscoped unfiltered searches and invalid folder scopes return error responses with appropriate error messages; includes test class asset metadata configuration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

codex

Suggested reviewers

  • dsarno
  • msanatan

Poem

🐰 A search that once had no gate,
Now validates before too late,
Paths are trimmed, filters checked with care,
Asset data loads just where needed there,
No more Unity hangs—the project runs fair!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: guarding manage_asset search against broad scans that could cause performance issues.
Description check ✅ Passed The PR description covers the summary, rationale, and validation steps, though it lacks the structured template format with explicit Type of Change, Testing checklist, and Documentation Updates sections.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #1177: malformed parameter normalization, rejection of empty/date-only searches, invalid folder scope rejection, pagination before GetAssetData, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #1177: search validation, parameter normalization, pagination optimization, and corresponding tests. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@liuzqk liuzqk force-pushed the fix/manage-asset-search-guard branch from f7e5c08 to 0f5a81e Compare May 31, 2026 06:22
@liuzqk liuzqk marked this pull request as ready for review May 31, 2026 06:53
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
MCPForUnity/Editor/Tools/ManageAsset.cs (1)

697-728: 💤 Low value

Performance optimization successfully defers asset data loading.

The search pipeline now collects matching paths first, applies pagination to the path list, and only calls GetAssetData() for the paginated subset. This prevents materializing full asset metadata for all matches when only a page is needed.

Minor edge case: If an asset is deleted between FindAssets and GetAssetData, the results list may contain a null entry (line 1050 returns null for non-existent assets). This is a rare race condition in practice, and the JSON response would just include a null entry that clients should handle gracefully.

Optional: Filter out null entries after GetAssetData

If you want to ensure no null entries in the response:

-                var pagedResults = matchingPaths
-                    .Skip(startIndex)
-                    .Take(pageSize)
-                    .Select(assetPath => GetAssetData(assetPath, generatePreview))
-                    .ToList();
+                var pagedResults = matchingPaths
+                    .Skip(startIndex)
+                    .Take(pageSize)
+                    .Select(assetPath => GetAssetData(assetPath, generatePreview))
+                    .Where(data => data != null)
+                    .ToList();

Note: This would cause pagedResults.Count to potentially be less than pageSize if some assets were deleted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MCPForUnity/Editor/Tools/ManageAsset.cs` around lines 697 - 728, The
pagedResults list can contain nulls if assets are deleted between
AssetDatabase.FindAssets and GetAssetData; after creating pagedResults via
matchingPaths.Skip(...).Take(...).Select(...).ToList(), filter out null entries
(e.g., remove or Where(x => x != null)) and adjust total/result counts
accordingly so callers don't receive null entries; update references to
GetAssetData, matchingPaths and pagedResults in ManageAsset.cs to perform this
null-filtering and ensure pagination/counts reflect the filtered results.
Server/tests/integration/test_manage_asset_search_guard.py (2)

37-46: ⚡ Quick win

Test validates rejection but doesn't verify the semantic constraint.

The test correctly confirms that a date-only search without scope or type filter is rejected. However, the assertion on line 45 only checks that "filter_type" appears in the generic error message. Consider adding a positive test case that verifies adding filter_type makes the date search valid, which would more clearly document the intended behavior that date filters should be combined with type filters or folder scopes.

🧪 Suggested enhancement

Add a positive test after this one:

`@pytest.mark.asyncio`
async def test_search_date_filter_with_type_succeeds(monkeypatch):
    captured = {}

    async def fake_send(send_fn, unity_instance, command_type, params, **kwargs):
        captured["params"] = params
        return {"success": True, "data": {"assets": []}}

    monkeypatch.setattr(
        "services.tools.manage_asset.send_with_unity_instance",
        fake_send,
    )

    result = await manage_asset(
        ctx=DummyContext(),
        action="search",
        path="Assets",
        filter_type="Prefab",
        filter_date_after="2026-01-01T00:00:00Z",
    )

    assert result["success"] is True
    assert captured["params"]["filterDateAfter"] == "2026-01-01T00:00:00Z"
    assert captured["params"]["filterType"] == "Prefab"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Server/tests/integration/test_manage_asset_search_guard.py` around lines 37 -
46, The test ensures a date-only search is rejected but doesn't verify the
complementary positive behavior; add a new async test (e.g.,
test_search_date_filter_with_type_succeeds) that monkeypatches
services.tools.manage_asset.send_with_unity_instance to capture params, calls
manage_asset(ctx=DummyContext(), action="search", path="Assets",
filter_type="Prefab", filter_date_after="2026-01-01T00:00:00Z"), asserts
result["success"] is True, and verifies the captured params include
filterDateAfter == "2026-01-01T00:00:00Z" and filterType == "Prefab" so the
semantic constraint (date filter must be combined with type or scope) is
validated.

23-24: 💤 Low value

Consider a more specific assertion.

The assertion only checks for "search_pattern" in the error message, but the actual message contains both "search_pattern" and "filter_type". A more robust assertion would verify the complete intent (e.g., check for "requires" and both search criteria, or verify the full message structure) to prevent false positives if the error message changes.

📋 Suggested refinement
     assert result["success"] is False
-    assert "search_pattern" in result["message"]
+    assert "requires" in result["message"]
+    assert "search_pattern" in result["message"] or "filter" in result["message"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Server/tests/integration/test_manage_asset_search_guard.py` around lines 23 -
24, Update the test assertion to be more specific: instead of only checking that
"search_pattern" appears in result["message"], assert that the message mentions
both required fields (e.g., contains "search_pattern" and "filter_type") and the
intent (for example contains the word "requires" or match the full expected
error string). Locate the assertions in the test (the two lines asserting
result["success"] is False and checking result["message"]) and replace the loose
substring check with either two substring assertions for "search_pattern" and
"filter_type" or a single equality/assertion against the full expected error
message to ensure the test fails if the message changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@MCPForUnity/Editor/Tools/ManageAsset.cs`:
- Around line 697-728: The pagedResults list can contain nulls if assets are
deleted between AssetDatabase.FindAssets and GetAssetData; after creating
pagedResults via matchingPaths.Skip(...).Take(...).Select(...).ToList(), filter
out null entries (e.g., remove or Where(x => x != null)) and adjust total/result
counts accordingly so callers don't receive null entries; update references to
GetAssetData, matchingPaths and pagedResults in ManageAsset.cs to perform this
null-filtering and ensure pagination/counts reflect the filtered results.

In `@Server/tests/integration/test_manage_asset_search_guard.py`:
- Around line 37-46: The test ensures a date-only search is rejected but doesn't
verify the complementary positive behavior; add a new async test (e.g.,
test_search_date_filter_with_type_succeeds) that monkeypatches
services.tools.manage_asset.send_with_unity_instance to capture params, calls
manage_asset(ctx=DummyContext(), action="search", path="Assets",
filter_type="Prefab", filter_date_after="2026-01-01T00:00:00Z"), asserts
result["success"] is True, and verifies the captured params include
filterDateAfter == "2026-01-01T00:00:00Z" and filterType == "Prefab" so the
semantic constraint (date filter must be combined with type or scope) is
validated.
- Around line 23-24: Update the test assertion to be more specific: instead of
only checking that "search_pattern" appears in result["message"], assert that
the message mentions both required fields (e.g., contains "search_pattern" and
"filter_type") and the intent (for example contains the word "requires" or match
the full expected error string). Locate the assertions in the test (the two
lines asserting result["success"] is False and checking result["message"]) and
replace the loose substring check with either two substring assertions for
"search_pattern" and "filter_type" or a single equality/assertion against the
full expected error message to ensure the test fails if the message changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 503abe1b-df5a-4831-9369-9dc77f3963ae

📥 Commits

Reviewing files that changed from the base of the PR and between 2d2bdc5 and 0f5a81e.

📒 Files selected for processing (5)
  • MCPForUnity/Editor/Tools/ManageAsset.cs
  • Server/src/services/tools/manage_asset.py
  • Server/tests/integration/test_manage_asset_search_guard.py
  • TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageAssetSearchGuardTests.cs
  • TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ManageAssetSearchGuardTests.cs.meta

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: AI无法正确使用ManageAsset的Search action,且错误调用该工具会造成Unity卡死

1 participant