Ctrl K
ComunidadGuías…

developer_plugin_runtime.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package main

import (
	"context"
	"errors"
	"fmt"
	"net/http"

	"github.com/rs/zerolog/log"
	"netgoat.xyz/agent/internal/config"
	"netgoat.xyz/agent/internal/developerplugins"
	"netgoat.xyz/agent/internal/middleware"
)

// developerPluginRuntime owns the fixed middleware set selected during agent
// startup. It intentionally has no update method: remote catalog selections
// are restart-only and can never hot-load code into a serving process.
type developerPluginRuntime struct {
	registry *middleware.Registry
	active   []developerplugins.ResolvedInstallation
}

func newDeveloperPluginRuntime(cfg *config.Config) (*developerPluginRuntime, error) {
	plugins := config.PluginConfig{}
	if cfg != nil {
		plugins = cfg.Plugins.Clone()
	}
	resolved, err := developerplugins.NewBuiltinRegistry().ResolveAll(plugins)
	if err != nil {
		return nil, err
	}
	if len(resolved) == 0 {
		return &developerPluginRuntime{}, nil
	}

	registry := middleware.NewRegistry(
		middleware.CapabilityRequestRead,
		middleware.CapabilityRouteRead,
		middleware.CapabilityResponseWrite,
	)
	for _, selection := range resolved {
		plugin, err := selection.Descriptor.Factory(selection.Config)
		if err != nil {
			return nil, fmt.Errorf("create compiled plugin %q: %w", selection.Descriptor.PluginID, err)
		}
		if err := selection.Descriptor.VerifyPlugin(plugin); err != nil {
			return nil, err
		}
		if err := registry.Register(plugin, selection.Descriptor.GrantedCapabilities...); err != nil {
			return nil, fmt.Errorf("register compiled plugin %q: %w", selection.Descriptor.PluginID, err)
		}
	}
	if err := registry.Start(context.Background()); err != nil {
		return nil, fmt.Errorf("start compiled developer plugins: %w", err)
	}
	return &developerPluginRuntime{registry: registry, active: resolved}, nil
}

// Evaluate invokes the immutable startup registry after the proxy has resolved
// trusted client and route metadata. Returning false means the middleware
// wrote a blocking/error response, so callers must stop processing the request.
func (r *developerPluginRuntime) Evaluate(writer http.ResponseWriter, request *http.Request, metadata middleware.RequestMetadata) bool {
	if r == nil || r.registry == nil {
		return true
	}
	nextCalled := false
	r.registry.Handler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
		nextCalled = true
	})).ServeHTTP(writer, middleware.WithRequestMetadata(request, metadata))
	return nextCalled
}

func (r *developerPluginRuntime) Close(ctx context.Context) error {
	if r == nil || r.registry == nil {
		return nil
	}
	return r.registry.Close(ctx)
}

func (r *developerPluginRuntime) ActiveCount() int {
	if r == nil {
		return 0
	}
	return len(r.active)
}

func validateDeveloperPluginSelection(plugins config.PluginConfig) error {
	_, err := developerplugins.NewBuiltinRegistry().ResolveAll(plugins)
	return err
}

func closeDeveloperPluginRuntime(runtime *developerPluginRuntime) {
	if runtime == nil {
		return
	}
	if err := runtime.Close(context.Background()); err != nil && !errors.Is(err, context.Canceled) {
		log.Error().Err(err).Msg("Graceful developer plugin shutdown failed")
	}
}