Skip to content

Plugin loader: allow external plugins to override built-in step types #262

@intel352

Description

@intel352

Problem

In v0.3.11, the pipelinesteps plugin now registers a built-in step.authz_check step type. External plugins (e.g., workflow-plugin-authz) that also register step.authz_check fail to load via engine.LoadPlugin() because the plugin loader (plugin/loader.go line 146) rejects duplicate step type names.

Current Behavior

step type "step.authz_check" already registered

The plugin loader checks for duplicates and returns an error, preventing the external plugin from loading entirely.

Expected Behavior

External plugins should be able to override built-in step types. This is important because:

  1. The built-in step.authz_check only works with PolicyEngineModule (which only supports "mock" backend via resolvePolicyEngine() concrete type assertion)
  2. The external workflow-plugin-authz provides a Casbin-backed implementation that is production-ready
  3. External plugins should be treated as intentional overrides of built-in defaults

Workaround

We bypass the plugin loader entirely by registering external plugin factories directly via engine.AddModuleType() / engine.AddStepType() (which silently overwrite):

func registerExternalPlugin(engine *wf.StdEngine, p plugin.EnginePlugin) error {
    for typeName, factory := range p.ModuleFactories() {
        f := factory
        engine.AddModuleType(typeName, func(name string, cfg map[string]any) modular.Module {
            return f(name, cfg)
        })
    }
    for typeName, factory := range p.StepFactories() {
        capturedType := typeName
        capturedFactory := factory
        engine.AddStepType(typeName, func(name string, cfg map[string]any, app modular.Application) (module.PipelineStep, error) {
            result, err := capturedFactory(name, cfg, app)
            if err != nil {
                return nil, err
            }
            step, ok := result.(module.PipelineStep)
            if !ok {
                return nil, fmt.Errorf("external plugin step factory for %q returned non-PipelineStep type %T", capturedType, result)
            }
            return step, nil
        })
    }
    return nil
}

Suggested Fix

Option A: Allow LoadPlugin() to accept an override flag or option that permits replacing existing types.

Option B: Change the plugin loader to log a warning instead of returning an error when an external plugin registers a type that already exists, treating external plugins as intentional overrides.

Option C: Add an engine.LoadPluginWithOverride() method that uses the existing loader but skips the duplicate check.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions