chore(unity): 固定Unity CLI Loop本地包并移除UnitySkills依赖
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d61cff1f2623f4fedbd4355522e4677d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdb0edcbf39d74821b003eb0a8949747
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a178e2d2026914019a108c803763fff0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cf60c894bb934b72bfd4dee121a63de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user