Skip to content

User-Extensible Remediation Plugin System #181

@jtdub

Description

@jtdub

Is your feature request related to a problem? Please describe.

While the driver-based remediation transform callbacks (see related issue) solve the problem for platform-specific transforms built into hier_config, there's currently no way for end users to extend remediation behavior without modifying the hier_config source code or forking drivers.

Users in specialized environments often need custom remediation logic that:

  • Is specific to their organization's network policies
  • Shouldn't be included in the core hier_config distribution
  • Needs to be maintained separately from the main codebase
  • Should be shareable as independent packages within their organization

For example:

  • A financial services company might require multi-step certificate rotation with specific validation steps
  • A service provider might need custom BGP graceful shutdown sequences for their specific topology
  • A university might have unique VLAN provisioning workflows tied to their identity management system

Currently, users must either:

  1. Fork and modify driver code (hard to maintain across upgrades)
  2. Write complex post-processing scripts (breaks the cohesive driver design)
  3. Request their custom logic be added to hier_config core (inappropriate for org-specific needs)

Describe the solution you'd like

Create a plugin framework that allows users to register custom remediation transforms without modifying hier_config source code.

Proposed Architecture:

  1. Plugin Base Class (plugins.py):
from abc import ABC, abstractmethod
from hier_config import HConfig
from hier_config.models import MatchRule
 
class RemediationPlugin(ABC):
    """Base class for user-defined remediation plugins."""
 
    @property
    @abstractmethod
    def name(self) -> str:
        """Unique identifier for this plugin."""
        pass
 
    @property
    @abstractmethod
    def description(self) -> str:
        """Human-readable description of what this plugin does."""
        pass
 
    @property
    def applies_to(self) -> tuple[MatchRule, ...]:
        """Optional: MatchRules to filter which remediation sections this plugin processes.
        If not specified, plugin receives the entire remediation tree."""
        return ()
 
    @property
    def priority(self) -> int:
        """Execution order (lower numbers run first). Default: 100."""
        return 100
 
    @abstractmethod
    def transform(self, remediation: HConfig) -> None:
        """Apply the transformation to the remediation config.
 
        Args:
            remediation: The remediation HConfig tree (mutable)
        """
        pass
  1. Plugin Registration (extend HConfigDriverBase):
class HConfigDriverBase(ABC):
    def __init__(self) -> None:
        self.rules = self._instantiate_rules()
        self._user_plugins: list[RemediationPlugin] = []
 
    def register_plugin(self, plugin: RemediationPlugin) -> None:
        """Register a user-defined remediation plugin."""
        self._user_plugins.append(plugin)
        # Sort by priority
        self._user_plugins.sort(key=lambda p: p.priority)
 
    def unregister_plugin(self, plugin_name: str) -> None:
        """Remove a plugin by name."""
        self._user_plugins = [p for p in self._user_plugins if p.name != plugin_name]
  1. Integration with WorkflowRemediation (workflows.py):
@property
def remediation_config(self) -> HConfig:
    if self._remediation_config:
        return self._remediation_config
 
    remediation_config = self.running_config.config_to_get_to(
        self.generated_config
    ).set_order_weight()
 
    # Apply driver-native remediation transforms
    for callback in remediation_config.driver.rules.remediation_transform_callbacks:
        callback(remediation_config)
 
    # Apply user-registered plugins (sorted by priority)
    for plugin in remediation_config.driver._user_plugins:
        if plugin.applies_to:
            # Plugin targets specific sections
            for child in remediation_config.get_children_deep(plugin.applies_to):
                plugin.transform(child)
        else:
            # Plugin processes entire remediation tree
            plugin.transform(remediation_config)
 
    self._remediation_config = remediation_config
    return self._remediation_config
  1. User Implementation Example:
# my_company/network_plugins.py
 
from hier_config.plugins import RemediationPlugin
from hier_config import HConfig
from hier_config.models import MatchRule
 
class CompanyBGPGracefulShutdown(RemediationPlugin):
    """Adds graceful shutdown sequence for BGP peer changes."""
 
    name = "company_bgp_graceful_shutdown"
    description = "Wraps BGP peer config changes with graceful shutdown"
    priority = 50  # Run before other transforms
 
    applies_to = (
        MatchRule(startswith="router bgp"),
        MatchRule(contains="neighbor"),
    )
 
    def transform(self, remediation: HConfig) -> None:
        """Add shutdown before peer changes, no shutdown after."""
        for bgp_section in remediation.get_children(startswith="router bgp"):
            has_peer_changes = any(
                "neighbor" in child.text
                for child in bgp_section.children
            )
 
            if has_peer_changes:
                # Add graceful shutdown at the start
                shutdown = bgp_section.add_child("  graceful-shutdown activate")
                shutdown.order_weight = -2000
 
                # Remove graceful shutdown at the end
                reactivate = bgp_section.add_child("  no graceful-shutdown activate")
                reactivate.order_weight = 2000
 
# Usage in user's code:
from hier_config import get_hconfig_driver, Platform
from my_company.network_plugins import CompanyBGPGracefulShutdown
 
driver = get_hconfig_driver(Platform.CISCO_IOS)
driver.register_plugin(CompanyBGPGracefulShutdown())
 
# Now all workflows using this driver will apply the plugin
workflow = WorkflowRemediation(running, generated)
remediation = workflow.remediation_config  # Plugin automatically applied

Benefits:

  • ✅ Users can extend ohne modifying hier_config source
  • ✅ Plugins can be packaged and distributed separately (pip install my-company-network-plugins)
  • ✅ Multiple plugins can be composed (priority-based execution order)
  • ✅ Plugins are reusable across multiple workflows
  • ✅ Full access to HConfig API
  • ✅ Type-safe with abstract base class
  • ✅ Platform-agnostic (plugins work with any driver)
  • ✅ Optional filtering via applies_to MatchRules
  • ✅ Clean separation between core and user-specific logic

Describe alternatives you've considered

  1. Driver Subclassing (Current Workaround)

    • Users subclass driver and override methods
    • Cons: Requires forking, hard to maintain, can't easily share
  2. Global Registry

    • Plugins register globally instead of per-driver
    • Pros: Simpler registration
    • Cons: Unexpected behavior across different drivers, harder to scope
  3. Declarative Plugin Configuration

    • Define plugins via YAML/JSON configuration files
    • Pros: No code required for simple transforms
    • Cons: Limited flexibility, harder to debug
  4. Monkey Patching (Anti-pattern)

    • Users monkey-patch WorkflowRemediation
    • Cons: Fragile, breaks across versions, impossible to support

The plugin system provides the right balance of flexibility, maintainability, and hier_config compatibility.

Additional context

Relationship to Remediation Transform Callbacks:

This plugin system complements (not replaces) the driver-native remediation transform callbacks:

Feature Driver Callbacks Plugin System
Who defines it? hier_config maintainers End users
Where does it live? In driver source code External packages
Scope Platform-specific, universal Org-specific, customized
Examples Safe ACL remediation Company-specific BGP workflows
Execution Always runs (part of driver) Opt-in (user registers)

Execution Flow:

remediation_config property called
  ↓
1. Compute diff (config_to_get_to)
  ↓
2. Set order weights
  ↓
3. Apply driver-native callbacks (post_load_callbacks, remediation_transform_callbacks)
  ↓
4. Apply user-registered plugins (sorted by priority)
  ↓
5. Cache and return

Real-World Plugin Examples:

  1. Certificate Rotation with Validation
class SecureCertRotationPlugin(RemediationPlugin):
    """Multi-step certificate rotation with validation."""
    def transform(self, remediation):
        # 1. Install new cert
        # 2. Verify new cert is valid
        # 3. Switch active cert
        # 4. Keep old cert as backup for N days
  1. Compliance Audit Trail
class ComplianceAuditPlugin(RemediationPlugin):
    """Injects audit comments into remediation."""
    def transform(self, remediation):
        for change in remediation.all_children():
            change.add_child(f"! Audit: {ticket_number} - {timestamp}")
  1. QoS Safe Transition
class QoSSafeTransitionPlugin(RemediationPlugin):
    """Ensures QoS policy changes don't drop traffic."""
    def transform(self, remediation):
        # Create new policy → apply to interface → delete old policy

Implementation Phases:

  • Phase 1: Core plugin infrastructure (base class, registration, execution)
  • Phase 2: Plugin discovery (automatic loading from installed packages)
  • Phase 3: Plugin configuration (enable/disable, configure parameters)
  • Phase 4: Plugin marketplace/gallery (community-contributed plugins)

Alignment with hier_config Design Philosophy:

  • Composable - Multiple plugins can be combined
  • Declarative - applies_to uses MatchRule system
  • Hierarchical - Operates on HConfig tree structure
  • Platform Agnostic - Plugins work across all drivers
  • Extensible - Open for extension, closed for modification

Metadata

Metadata

Assignees

No one assigned

    Labels

    v4-enhancementEnhancement planned for hier_config v4.0.0

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions