chore(unity): 固定Unity CLI Loop本地包并移除UnitySkills依赖

This commit is contained in:
Liubing\LB
2026-09-28 18:14:59 +08:00
parent 0eb43b2b40
commit c4ae02def9
952 changed files with 70137 additions and 11 deletions

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace io.github.hatayama.uLoopMCP
{
/// <summary>
/// Assembly Reference Policy Based on Security Level
/// Related Classes: DynamicCodeSecurityLevel, DangerousApiDetector, RoslynCompiler
///
/// Design Principles:
/// - Disabled: No Assembly References (Compilation Not Allowed)
/// - Restricted/FullAccess: All Assembly References Allowed (Compilation Possible)
/// - Security Checks Performed at Runtime by DangerousApiDetector
///
/// Note:
/// - This class is declarative and is NOT consulted by RoslynCompiler when constructing
/// MetadataReference collections for compilation.
/// - The actual reference set is built inside RoslynCompiler.InitializeReferencesForLevel.
/// - In Restricted mode, safety is enforced by post-compilation validation (SecurityValidator /
/// DangerousApiDetector), rather than by filtering references at compile time.
/// </summary>
public static class AssemblyReferencePolicy
{
/// <summary>
/// Retrieve Assembly Name List Based on Security Level.
/// This list is intended for diagnostics and tests. It is not applied by RoslynCompiler
/// to include/exclude references during compilation.
/// </summary>
public static IReadOnlyList<string> GetAssemblies(DynamicCodeSecurityLevel level)
{
switch (level)
{
case DynamicCodeSecurityLevel.Restricted:
case DynamicCodeSecurityLevel.FullAccess:
// Level 1 & 2: All Assemblies Referenceable
// Security Checks Performed at Runtime
return GetAllAvailableAssemblies();
default:
VibeLogger.LogWarning(
"assembly_policy_unknown_level",
$"Unknown security level: {level}",
new { level = level.ToString() },
correlationId: McpConstants.GenerateCorrelationId(),
humanNote: "Unknown security level encountered",
aiTodo: "Review security level enum changes"
);
return new List<string>();
}
}
/// <summary>
/// Retrieve All Available Assemblies
/// </summary>
private static List<string> GetAllAvailableAssemblies()
{
List<string> assemblies = new();
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
// Exclude dynamic assemblies or those with empty locations
if (assembly.IsDynamic || string.IsNullOrWhiteSpace(assembly.Location))
continue;
string assemblyName = assembly.GetName().Name;
assemblies.Add(assemblyName);
}
VibeLogger.LogInfo(
"assembly_policy_all_assemblies",
"Generated all available assemblies list",
new { count = assemblies.Count },
correlationId: McpConstants.GenerateCorrelationId(),
humanNote: "All assemblies made available for compilation",
aiTodo: "Monitor assembly usage in dynamic code execution"
);
return assemblies;
}
/// <summary>
/// Check if the Specified Assembly is Allowed by Security Level
/// (Maintained for Backward Compatibility)
/// Note: This helper is not enforced by RoslynCompiler during reference construction.
/// </summary>
public static bool IsAssemblyAllowed(string assemblyName, DynamicCodeSecurityLevel level)
{
if (string.IsNullOrWhiteSpace(assemblyName))
return false;
switch (level)
{
case DynamicCodeSecurityLevel.Restricted:
case DynamicCodeSecurityLevel.FullAccess:
// Level 1 & 2: Allow Everything
return true;
default:
return false;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d61cff1f2623f4fedbd4355522e4677d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace io.github.hatayama.uLoopMCP
{
/// <summary>
/// Security management utility for ExecuteDynamicCodeTool
/// Related Classes: DynamicCodeSecurityLevel, AssemblyReferencePolicy, RoslynCompiler
/// </summary>
public static class DynamicCodeSecurityManager
{
/// <summary>
/// Check if code execution is possible at the specified security level
/// </summary>
public static bool CanExecute(DynamicCodeSecurityLevel level)
{
switch (level)
{
case DynamicCodeSecurityLevel.Restricted:
case DynamicCodeSecurityLevel.FullAccess:
// Level 1, 2: Execution permitted
return true;
default:
return false;
}
}
/// <summary>
/// Retrieve list of allowed assemblies based on the security level
/// </summary>
public static IReadOnlyList<string> GetAllowedAssemblies(DynamicCodeSecurityLevel level)
{
return AssemblyReferencePolicy.GetAssemblies(level);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdb0edcbf39d74821b003eb0a8949747
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,292 @@
using System;
using System.Reflection;
using UnityEngine;
namespace io.github.hatayama.uLoopMCP
{
/// <summary>
/// Security checker for Unity MCP tools - provides runtime tool blocking based on user settings
///
/// Design document reference: Packages/src/Editor/Security/SECURITY.md
///
/// Related classes:
/// - ULoopSettings: Persistent security settings storage (.uloop/settings.permissions.json)
/// - McpSecurityException: Custom exception for security violations
/// - UnityToolRegistry: Tool registration and execution
/// - McpBridgeServer: Server that executes tools
/// </summary>
public static class McpSecurityChecker
{
/// <summary>
/// Checks if a tool is allowed based on current security settings
/// </summary>
/// <param name="toolName">The name of the tool to check</param>
/// <returns>True if tool is allowed, false otherwise</returns>
public static bool IsToolAllowed(string toolName)
{
if (string.IsNullOrEmpty(toolName))
{
return false;
}
// Get tool info from registry
var toolInfo = GetToolSecurityInfoFromRegistry(toolName);
if (!toolInfo.HasValue)
{
// Unknown tool - default to block for security
return false;
}
return IsToolAllowedByAttribute(toolInfo.Value);
}
/// <summary>
/// Checks if a command is allowed based on current security settings
/// </summary>
/// <param name="commandName">The name of the command to check</param>
/// <returns>True if command is allowed, false otherwise</returns>
[System.Obsolete("Use IsToolAllowed instead. This method will be removed in a future version.")]
public static bool IsCommandAllowed(string commandName)
{
return IsToolAllowed(commandName);
}
/// <summary>
/// Gets tool security info from the tool registry
/// </summary>
/// <param name="toolName">The name of the tool</param>
/// <returns>Tool security info or null if not found</returns>
private static ToolAttributeInfo? GetToolSecurityInfoFromRegistry(string toolName)
{
// Get the tool registry instance
var registry = CustomToolManager.GetRegistry();
if (registry == null)
{
return null;
}
// Find the tool and get its attribute
var toolType = registry.GetToolType(toolName);
if (toolType == null)
{
return null;
}
var attribute = toolType.GetCustomAttribute<McpToolAttribute>();
if (attribute == null)
{
return new ToolAttributeInfo(toolName, SecuritySettings.None);
}
return new ToolAttributeInfo(toolName, attribute.RequiredSecuritySetting);
}
/// <summary>
/// Checks if tool is allowed based on its attribute settings
/// </summary>
/// <param name="toolInfo">Tool attribute information</param>
/// <returns>True if tool is allowed</returns>
private static bool IsToolAllowedByAttribute(ToolAttributeInfo toolInfo)
{
switch (toolInfo.RequiredSecuritySetting)
{
case SecuritySettings.None:
return IsThirdPartyToolAllowed(toolInfo.ToolName);
default:
return false; // Unknown setting - block by default
}
}
/// <summary>
/// Validates tool execution and throws exception if blocked
/// </summary>
/// <param name="toolName">The name of the tool to validate</param>
/// <param name="throwOnBlock">If true, throws exception when blocked. If false, returns validation result.</param>
/// <returns>True if tool is allowed</returns>
/// <exception cref="McpSecurityException">Thrown when tool is blocked and throwOnBlock is true</exception>
public static bool ValidateTool(string toolName, bool throwOnBlock = true)
{
if (IsToolAllowed(toolName))
{
return true;
}
string reason = GetBlockReason(toolName);
if (throwOnBlock)
{
throw new McpSecurityException(toolName, reason);
}
return false;
}
/// <summary>
/// Validates command execution and throws exception if blocked
/// </summary>
/// <param name="commandName">The name of the command to validate</param>
/// <param name="throwOnBlock">If true, throws exception when blocked. If false, returns validation result.</param>
/// <returns>True if command is allowed</returns>
/// <exception cref="McpSecurityException">Thrown when command is blocked and throwOnBlock is true</exception>
[System.Obsolete("Use ValidateTool instead. This method will be removed in a future version.")]
public static bool ValidateCommand(string commandName, bool throwOnBlock = true)
{
return ValidateTool(commandName, throwOnBlock);
}
/// <summary>
/// Gets the user-friendly reason why a tool is blocked
/// </summary>
/// <param name="toolName">The name of the tool</param>
/// <returns>Human-readable reason string</returns>
public static string GetBlockReason(string toolName)
{
var toolInfo = GetToolSecurityInfoFromRegistry(toolName);
if (!toolInfo.HasValue)
{
return $"Tool '{toolName}' is not allowed by security policy.";
}
switch (toolInfo.Value.RequiredSecuritySetting)
{
case SecuritySettings.None:
if (IsThirdPartyTool(toolName))
{
return "Third party tools execution is disabled. Enable 'Allow Third Party Tools' in uLoopMCP Security Settings.";
}
return $"Tool '{toolName}' is not allowed by security policy.";
default:
return $"Tool '{toolName}' is not allowed by security policy.";
}
}
/// <summary>
/// Gets security information for a tool
/// </summary>
/// <param name="toolName">The name of the tool</param>
/// <returns>Security information object</returns>
public static ToolSecurityInfo GetToolSecurityInfo(string toolName)
{
bool isAllowed = IsToolAllowed(toolName);
string reason = isAllowed ? "Tool is allowed" : GetBlockReason(toolName);
return new ToolSecurityInfo(toolName, isAllowed, reason);
}
/// <summary>
/// Checks if third party tools execution is allowed
/// </summary>
/// <returns>True if third party tools execution is allowed</returns>
private static bool IsThirdPartyToolsAllowed()
{
return ULoopSettings.GetAllowThirdPartyTools();
}
/// <summary>
/// Checks if a specific tool is allowed (considers both explicit setting and third party status)
/// </summary>
/// <param name="toolName">The name of the tool to check</param>
/// <returns>True if tool is allowed</returns>
private static bool IsThirdPartyToolAllowed(string toolName)
{
// If it's not a third party tool (i.e., official tool), allow it
if (!IsThirdPartyTool(toolName))
{
return true;
}
// If it's a third party tool, check the setting
return IsThirdPartyToolsAllowed();
}
/// <summary>
/// Checks if a tool is a third party tool based on its assembly
/// </summary>
/// <param name="toolName">The name of the tool to check</param>
/// <returns>True if tool is from a third party assembly</returns>
private static bool IsThirdPartyTool(string toolName)
{
// Get tool type from registry
var registry = CustomToolManager.GetRegistry();
if (registry == null)
{
return true; // Default to third party if registry unavailable
}
var toolType = registry.GetToolType(toolName);
if (toolType == null)
{
return true; // Default to third party if tool type not found
}
// Check assembly name
string assemblyName = toolType.Assembly.GetName().Name;
// Official uLoopMCP assembly
return assemblyName != "uLoopMCP.Editor";
}
}
/// <summary>
/// Security information for a tool
/// </summary>
public readonly struct ToolSecurityInfo
{
public readonly string ToolName;
public readonly bool IsAllowed;
public readonly string Reason;
public ToolSecurityInfo(string toolName, bool isAllowed, string reason)
{
ToolName = toolName;
IsAllowed = isAllowed;
Reason = reason;
}
}
/// <summary>
/// Tool attribute information for security checking
/// </summary>
internal readonly struct ToolAttributeInfo
{
public readonly string ToolName;
public readonly SecuritySettings RequiredSecuritySetting;
public ToolAttributeInfo(string toolName, SecuritySettings requiredSecuritySetting)
{
ToolName = toolName;
RequiredSecuritySetting = requiredSecuritySetting;
}
}
/// <summary>
/// Exception thrown when a tool is blocked by security settings
/// </summary>
public class McpSecurityException : Exception
{
public string ToolName { get; }
public string SecurityReason { get; }
/// <summary>
/// Backwards compatibility property for CommandName
/// </summary>
[System.Obsolete("Use ToolName instead. This property will be removed in a future version.")]
public string CommandName => ToolName;
public McpSecurityException(string toolName, string reason)
: base($"Tool '{toolName}' is blocked by security settings: {reason}")
{
ToolName = toolName;
SecurityReason = reason;
}
public McpSecurityException(string toolName, string reason, Exception innerException)
: base($"Tool '{toolName}' is blocked by security settings: {reason}", innerException)
{
ToolName = toolName;
SecurityReason = reason;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a178e2d2026914019a108c803763fff0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
namespace io.github.hatayama.uLoopMCP
{
/// <summary>
/// Defines enum for security settings types
/// Each security setting controls the execution of specific commands
///
/// Related classes:
/// - McpSecurityChecker: Main security check logic
/// - McpToolAttribute: Attribute to specify command security settings
/// - RunTestsTool: Test execution tool
/// </summary>
public enum SecuritySettings
{
None,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9cf60c894bb934b72bfd4dee121a63de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: