Add scripts for resolving and verifying Chromium binary paths
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Docs CI / lint-and-preview (push) Has been cancelled
				
			- Implemented `chrome-path.js` to define functions for locating Chromium binaries across different platforms and nested directories. - Added `verify-chromium.js` to check for the presence of the Chromium binary and log the results, including candidate paths checked. - The scripts support Linux, Windows, and macOS environments, enhancing the flexibility of Chromium binary detection.
This commit is contained in:
		| @@ -0,0 +1,147 @@ | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.ObjectModel; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using StellaOps.Plugin; | ||||
| using StellaOps.Plugin.Hosting; | ||||
| using StellaOps.Scanner.Core.Security; | ||||
|  | ||||
| namespace StellaOps.Scanner.Analyzers.Lang.Plugin; | ||||
|  | ||||
| public interface ILanguageAnalyzerPluginCatalog | ||||
| { | ||||
|     IReadOnlyCollection<ILanguageAnalyzerPlugin> Plugins { get; } | ||||
|  | ||||
|     void LoadFromDirectory(string directory, bool seal = true); | ||||
|  | ||||
|     IReadOnlyList<ILanguageAnalyzer> CreateAnalyzers(IServiceProvider services); | ||||
| } | ||||
|  | ||||
| public sealed class LanguageAnalyzerPluginCatalog : ILanguageAnalyzerPluginCatalog | ||||
| { | ||||
|     private readonly ILogger<LanguageAnalyzerPluginCatalog> _logger; | ||||
|     private readonly IPluginCatalogGuard _guard; | ||||
|     private readonly ConcurrentDictionary<string, Assembly> _assemblies = new(StringComparer.OrdinalIgnoreCase); | ||||
|     private IReadOnlyList<ILanguageAnalyzerPlugin> _plugins = Array.Empty<ILanguageAnalyzerPlugin>(); | ||||
|  | ||||
|     public LanguageAnalyzerPluginCatalog(IPluginCatalogGuard guard, ILogger<LanguageAnalyzerPluginCatalog> logger) | ||||
|     { | ||||
|         _guard = guard ?? throw new ArgumentNullException(nameof(guard)); | ||||
|         _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||||
|     } | ||||
|  | ||||
|     public IReadOnlyCollection<ILanguageAnalyzerPlugin> Plugins => _plugins; | ||||
|  | ||||
|     public void LoadFromDirectory(string directory, bool seal = true) | ||||
|     { | ||||
|         ArgumentException.ThrowIfNullOrWhiteSpace(directory); | ||||
|         var fullDirectory = Path.GetFullPath(directory); | ||||
|  | ||||
|         var options = new PluginHostOptions | ||||
|         { | ||||
|             PluginsDirectory = fullDirectory, | ||||
|             EnsureDirectoryExists = false, | ||||
|             RecursiveSearch = false, | ||||
|         }; | ||||
|         options.SearchPatterns.Add("StellaOps.Scanner.Analyzers.*.dll"); | ||||
|  | ||||
|         var result = PluginHost.LoadPlugins(options, _logger); | ||||
|         if (result.Plugins.Count == 0) | ||||
|         { | ||||
|             _logger.LogWarning("No language analyzer plug-ins discovered under '{Directory}'.", fullDirectory); | ||||
|         } | ||||
|  | ||||
|         foreach (var descriptor in result.Plugins) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 _guard.EnsureRegistrationAllowed(descriptor.AssemblyPath); | ||||
|                 _assemblies[descriptor.AssemblyPath] = descriptor.Assembly; | ||||
|                 _logger.LogInformation( | ||||
|                     "Registered language analyzer plug-in assembly '{Assembly}' from '{Path}'.", | ||||
|                     descriptor.Assembly.FullName, | ||||
|                     descriptor.AssemblyPath); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _logger.LogError(ex, "Failed to register language analyzer plug-in '{Path}'.", descriptor.AssemblyPath); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         RefreshPluginList(); | ||||
|  | ||||
|         if (seal) | ||||
|         { | ||||
|             _guard.Seal(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public IReadOnlyList<ILanguageAnalyzer> CreateAnalyzers(IServiceProvider services) | ||||
|     { | ||||
|         ArgumentNullException.ThrowIfNull(services); | ||||
|  | ||||
|         if (_plugins.Count == 0) | ||||
|         { | ||||
|             _logger.LogWarning("No language analyzer plug-ins available; skipping language analysis."); | ||||
|             return Array.Empty<ILanguageAnalyzer>(); | ||||
|         } | ||||
|  | ||||
|         var analyzers = new List<ILanguageAnalyzer>(_plugins.Count); | ||||
|  | ||||
|         foreach (var plugin in _plugins) | ||||
|         { | ||||
|             if (!IsPluginAvailable(plugin, services)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 var analyzer = plugin.CreateAnalyzer(services); | ||||
|                 if (analyzer is null) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 analyzers.Add(analyzer); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _logger.LogError(ex, "Language analyzer plug-in '{Plugin}' failed to create analyzer instance.", plugin.Name); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (analyzers.Count == 0) | ||||
|         { | ||||
|             _logger.LogWarning("All language analyzer plug-ins were unavailable."); | ||||
|             return Array.Empty<ILanguageAnalyzer>(); | ||||
|         } | ||||
|  | ||||
|         analyzers.Sort(static (a, b) => string.CompareOrdinal(a.Id, b.Id)); | ||||
|         return new ReadOnlyCollection<ILanguageAnalyzer>(analyzers); | ||||
|     } | ||||
|  | ||||
|     private void RefreshPluginList() | ||||
|     { | ||||
|         var assemblies = _assemblies.Values.ToArray(); | ||||
|         var plugins = PluginLoader.LoadPlugins<ILanguageAnalyzerPlugin>(assemblies); | ||||
|         _plugins = plugins is IReadOnlyList<ILanguageAnalyzerPlugin> list | ||||
|             ? list | ||||
|             : new ReadOnlyCollection<ILanguageAnalyzerPlugin>(plugins.ToArray()); | ||||
|     } | ||||
|  | ||||
|     private static bool IsPluginAvailable(ILanguageAnalyzerPlugin plugin, IServiceProvider services) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return plugin.IsAvailable(services); | ||||
|         } | ||||
|         catch | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user