Skip to content

Add custom plugin registry #188

Open

Description

@andrei2699

a custom plugin registry should be able to be configured, in the same idea how the dxworks sdk is used


Some ideas

Custom Plugin Registry Support Plan (Parked)

This document contains the implementation plan designed to support custom plugin registries (both HTTP and Git) securely via configuration. This feature is parked for future implementation.

Overview

The goal is to support multiple custom plugin registries securely, integrating smoothly with the pre-existing DxWorks.Hub.Sdk structure. We will use the HttpClientFactory and named clients approach to pass auth headers for downloads natively.

Proposed Changes

Configuration Models

[NEW] ScriptBee.Domain.Model.Plugins.MarketPlace.RegistryConfig

Add a new record representing generic registries. To handle "git" vs "http" uniformly without bloating the object, we use a Properties dictionary for custom traits.

public record RegistryConfig
{
    public string Id { get; init; }
    public string Url { get; init; }
    public string Type { get; init; } // "git" or "http"
    public Dictionary<string, string>? Properties { get; init; } // Tokens, ProjectsPath, AuthHeader, etc.
}

Models

[MODIFY] ScriptBeeWebApp\src\Common\Model\Plugins\MarketPlace\MarketPlacePlugin.cs & PluginVersion.cs

Update MarketPlacePlugin and PluginVersion to expose the RegistryId (so the UI can filter them in the future) and an optional Checksum for verification.

// PluginVersion: add RegistryId and Checksum
public sealed record PluginVersion(string Url, Version Version, string ManifestUrl, string RegistryId, string? Checksum = null);

// MarketPlacePlugin: add RegistryId
public sealed record MarketPlacePlugin(string Id, string Name, string RegistryId, MarketPlacePluginType Type, ...)

Plugin Fetchers (IMarketPluginFetcher)

We will reuse the existing IMarketPluginFetcher interface, adapting it to support multiple registries so we can inject them as IEnumerable<IMarketPluginFetcher>.

[MODIFY] ScriptBeeWebApp\src\Common\Marketplace.Client\IMarketPluginFetcher.cs

Add the registry ID to the interface:

public interface IMarketPluginFetcher
{
    string RegistryId { get; }
    Task<IEnumerable<MarketPlacePlugin>> GetProjectsAsync(CancellationToken cancellationToken);
}

[MODIFY] ScriptBeeWebApp\src\Common\Marketplace.Client\MarketPluginFetcher.cs (DxWorks)

Will represent the default dxworks plugin fetcher (updating to handle its specific RegistryId).

[NEW] ScriptBeeWebApp\src\Common\Marketplace.Client\HttpMarketPluginFetcher.cs

Uses a named HttpClient (identified by RegistryId) to fetch JSON containing the list of available plugins, mapping them to MarketPlacePlugin.

[NEW/MODIFY] dxworks-hub-sdk integration for Git Registries

We will use the DxWorks.Hub.Sdk to handle "git" registries.

  1. Modify DxWorks.Hub.Sdk models (DxWorksHubSdkOptions and RepositoryManager) to support a custom ProjectsPath (folder where JSON projects are searched).
  2. Within ScriptBee, add a GitMarketPluginFetcher that creates a local IDxWorksHubClient instance configured with the registry's Url and Properties["ProjectsPath"] to clone and resolve plugins just like the default dxworks registry.

[NEW] ScriptBeeWebApp\src\Common\Marketplace.Client\AggregateMarketPluginFetcher.cs

A new implementation of IMarketPluginFetcher that aggregates results from all injected IEnumerable<IMarketPluginFetcher>. This class will be injected into GetAvailablePluginsService and could later accept filters by registryId.

Installation & Download

[MODIFY] ScriptBeeWebApp\src\Plugins\Plugins.Installer\IDownloadService.cs & DownloadService.cs

Change the interface to take a RegistryId and Checksum:

Task DownloadFileAsync(string url, string filePath, string registryId, string? checksum = null, CancellationToken cancellationToken = default);

Refactor DownloadService to inject IHttpClientFactory. When downloading, it creates the named client: var client = httpClientFactory.CreateClient(registryId);.
If checksum is provided, generate a SHA-256 hash post-download and verify. Throw an error if it fails.

[MODIFY] ScriptBeeWebApp\src\Common\Marketplace.Client\PluginUrlFetcher.cs & IPluginUrlFetcher.cs

Instead of returning OneOf<string, ...> (just URL), create a PluginDownloadInfo record that contains Url, RegistryId, and Checksum:

public record PluginDownloadInfo(string Url, string RegistryId, string? Checksum);

Update SimplePluginInstaller.cs and BundlePluginInstaller.cs to pass this object to IDownloadService.

Dependency Injection

[MODIFY] ScriptBeeWebApp\src\Common\Marketplace.Client\Extensions\ScriptBeeMarketplaceClientExtensions.cs

Read RegistryConfig from the settings ("ScriptBee:Registries"). For each config:

  • If "http", configure named HttpClients using .AddHttpClient(registry.Id). Set default headers with AuthHeader and Token if present in registry.Properties. Register an HttpMarketPluginFetcher instance.
  • If "git", construct a GitMarketPluginFetcher using DxWorks.Hub.Sdk client configured via the git url and properties.

Inject an AggregateMarketPluginFetcher as the primary resolver for GetAvailablePluginsService.

Verification/Testing Notes

  • Validate appsettings.json loads RegistryConfig property dictionaries properly.
  • Unit Tests for Registry Parsing, Checksum validation, and Named HttpClient resolution.
  • Verify that DownloadService receives the correct RegistryId to instantiate the appropriate named HttpClient.

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions