Skip to content

Bundle Reference

API-level reference for the SecretZero provider bundle framework. For a practical walkthrough, see Extending SecretZero.

BundleManifest

BundleManifest

Bases: BaseModel

Manifest describing a SecretZero provider bundle.

A bundle is a pip-installable package that contributes one or more of: a provider class, generator kinds, and target kinds to SecretZero.

Bundles register themselves via Python entry_points under the secretzero.providers group, and the bundle registry discovers them automatically at startup.

Attributes:

Name Type Description
name str

Unique bundle identifier (e.g. "github", "aws").

version str

Semantic version string for the bundle.

provider_class str | None

Dotted path to the provider class ("module.path:ClassName"), or None if the bundle only contributes generators/targets.

generators dict[str, str]

Mapping of generator kind string to dotted class path.

targets dict[str, str]

Mapping of target kind string to dotted class path.

generator_kinds list[str]

Optional list of new GeneratorKind enum values this bundle declares (informational; enums are open by default).

target_kinds list[str]

Optional list of new TargetKind enum values this bundle declares (informational; enums are open by default).

Source code in src/secretzero/bundles/registry.py
class BundleManifest(BaseModel):
    """Manifest describing a SecretZero provider bundle.

    A bundle is a pip-installable package that contributes one or more of:
    a provider class, generator kinds, and target kinds to SecretZero.

    Bundles register themselves via Python ``entry_points`` under the
    ``secretzero.providers`` group, and the bundle registry discovers
    them automatically at startup.

    Attributes:
        name: Unique bundle identifier (e.g. ``"github"``, ``"aws"``).
        version: Semantic version string for the bundle.
        provider_class: Dotted path to the provider class
            (``"module.path:ClassName"``), or ``None`` if the bundle
            only contributes generators/targets.
        generators: Mapping of generator kind string to dotted class path.
        targets: Mapping of target kind string to dotted class path.
        generator_kinds: Optional list of new ``GeneratorKind`` enum values
            this bundle declares (informational; enums are open by default).
        target_kinds: Optional list of new ``TargetKind`` enum values this
            bundle declares (informational; enums are open by default).
    """

    name: str = Field(description="Unique bundle identifier (e.g. 'github', 'aws')")
    version: str = Field(default="1.0.0", description="Bundle version")
    provider_class: str | None = Field(
        default=None,
        description="Dotted path to provider class ('module.path:ClassName')",
    )
    generators: dict[str, str] = Field(
        default_factory=dict,
        description="Mapping of generator kind string to dotted class path",
    )
    targets: dict[str, str] = Field(
        default_factory=dict,
        description="Mapping of target kind string to dotted class path",
    )
    generator_kinds: list[str] = Field(
        default_factory=list,
        description="New GeneratorKind enum values declared by this bundle",
    )
    target_kinds: list[str] = Field(
        default_factory=list,
        description="New TargetKind enum values declared by this bundle",
    )

BundleRegistry

BundleRegistry

Central registry for provider bundles, generators, targets, and providers.

The registry maps string kind identifiers to their corresponding classes, enabling the sync engine to look up implementations without hard-coded if/elif chains.

Built-in generators, targets, and providers are pre-registered at startup. Third-party bundles are discovered via Python entry_points (group "secretzero.providers").

Usage::

registry = get_bundle_registry()
generator_class = registry.get_generator_class("random_password")
target_class = registry.get_target_class("github_secret")
provider_class = registry.get_provider_class("aws")
Source code in src/secretzero/bundles/registry.py
class BundleRegistry:
    """Central registry for provider bundles, generators, targets, and providers.

    The registry maps string kind identifiers to their corresponding classes,
    enabling the sync engine to look up implementations without hard-coded
    ``if/elif`` chains.

    Built-in generators, targets, and providers are pre-registered at
    startup.  Third-party bundles are discovered via Python ``entry_points``
    (group ``"secretzero.providers"``).

    Usage::

        registry = get_bundle_registry()
        generator_class = registry.get_generator_class("random_password")
        target_class = registry.get_target_class("github_secret")
        provider_class = registry.get_provider_class("aws")
    """

    def __init__(self) -> None:
        """Initialize an empty bundle registry."""
        self._bundles: dict[str, BundleManifest] = {}
        self._generator_classes: dict[str, type] = {}
        self._target_classes: dict[str, type] = {}
        self._provider_classes: dict[str, type] = {}

    # ------------------------------------------------------------------
    # Registration
    # ------------------------------------------------------------------

    def register_bundle(self, manifest: BundleManifest) -> None:
        """Register all classes declared in a bundle manifest.

        Classes that cannot be imported (e.g. missing optional dependency)
        are silently skipped for graceful degradation.

        Args:
            manifest: The bundle manifest to register.
        """
        self._bundles[manifest.name] = manifest

        if manifest.provider_class:
            cls = load_class_safe(manifest.provider_class)
            if cls is not None:
                self._provider_classes[manifest.name] = cls

        for kind, path in manifest.generators.items():
            cls = load_class_safe(path)
            if cls is not None:
                self._generator_classes[kind] = cls

        for kind, path in manifest.targets.items():
            cls = load_class_safe(path)
            if cls is not None:
                self._target_classes[kind] = cls

    def register_generator(self, kind: str, cls: type) -> None:
        """Directly register a generator class by kind.

        Args:
            kind: Generator kind identifier (e.g. ``"random_password"``).
            cls: Generator class to register.
        """
        self._generator_classes[kind] = cls

    def register_target(self, kind: str, cls: type) -> None:
        """Directly register a target class by kind.

        Args:
            kind: Target kind identifier (e.g. ``"file"``).
            cls: Target class to register.
        """
        self._target_classes[kind] = cls

    def register_provider(self, kind: str, cls: type) -> None:
        """Directly register a provider class by kind.

        Args:
            kind: Provider kind identifier (e.g. ``"aws"``).
            cls: Provider class to register.
        """
        self._provider_classes[kind] = cls

    # ------------------------------------------------------------------
    # Discovery
    # ------------------------------------------------------------------

    def discover_and_register(self) -> None:
        """Auto-discover installed bundles via Python ``entry_points``.

        Iterates over all packages that have registered an entry point
        under the ``"secretzero.providers"`` group.  Each entry point
        value must be a :class:`BundleManifest` instance; others are
        silently skipped.
        """
        for ep in importlib.metadata.entry_points(group="secretzero.providers"):
            try:
                manifest = ep.load()
                if isinstance(manifest, BundleManifest):
                    self.register_bundle(manifest)
            except Exception:
                pass  # graceful degradation: never crash on bad bundles

    # ------------------------------------------------------------------
    # Lookups
    # ------------------------------------------------------------------

    def get_generator_class(self, kind: str) -> type | None:
        """Return the generator class for *kind*, or ``None`` if unknown.

        Args:
            kind: Generator kind string (e.g. ``"random_password"``).

        Returns:
            Generator class or ``None``.
        """
        return self._generator_classes.get(kind)

    def get_target_class(self, kind: str) -> type | None:
        """Return the target class for *kind*, or ``None`` if unknown.

        Args:
            kind: Target kind string (e.g. ``"github_secret"``).

        Returns:
            Target class or ``None``.
        """
        return self._target_classes.get(kind)

    def get_provider_class(self, kind: str) -> type | None:
        """Return the provider class for *kind*, or ``None`` if unknown.

        Args:
            kind: Provider kind string (e.g. ``"aws"``).

        Returns:
            Provider class or ``None``.
        """
        return self._provider_classes.get(kind)

    # ------------------------------------------------------------------
    # Introspection
    # ------------------------------------------------------------------

    def list_bundles(self) -> list[str]:
        """Return a sorted list of all registered bundle names.

        Returns:
            Sorted list of bundle name strings.
        """
        return sorted(self._bundles.keys())

    def list_generator_kinds(self) -> list[str]:
        """Return a sorted list of all registered generator kind strings.

        Returns:
            Sorted list of generator kind strings.
        """
        return sorted(self._generator_classes.keys())

    def list_target_kinds(self) -> list[str]:
        """Return a sorted list of all registered target kind strings.

        Returns:
            Sorted list of target kind strings.
        """
        return sorted(self._target_classes.keys())

    def list_provider_kinds(self) -> list[str]:
        """Return a sorted list of all registered provider kind strings.

        Returns:
            Sorted list of provider kind strings.
        """
        return sorted(self._provider_classes.keys())

    def get_bundle(self, name: str) -> BundleManifest | None:
        """Return the manifest for a registered bundle, or ``None``.

        Args:
            name: Bundle name.

        Returns:
            BundleManifest or ``None``.
        """
        return self._bundles.get(name)

    def validate_bundle_manifest(self, manifest: BundleManifest) -> list[str]:
        """Validate that all dotted paths in a manifest can be resolved.

        Checks that each declared class path is importable, inherits from
        the appropriate base class, and is callable.

        Args:
            manifest: The manifest to validate.

        Returns:
            List of error strings.  An empty list means the manifest is valid.
        """
        from secretzero.bundles.loader import load_class
        from secretzero.generators.base import BaseGenerator
        from secretzero.providers.base import BaseProvider
        from secretzero.targets.base import BaseTarget

        errors: list[str] = []

        if manifest.provider_class:
            try:
                cls = load_class(manifest.provider_class)
                if not (isinstance(cls, type) and issubclass(cls, BaseProvider)):
                    errors.append(
                        f"provider_class '{manifest.provider_class}' must subclass BaseProvider"
                    )
            except (ImportError, AttributeError, ValueError) as exc:
                errors.append(f"provider_class '{manifest.provider_class}': {exc}")

        for kind, path in manifest.generators.items():
            try:
                cls = load_class(path)
                if not (isinstance(cls, type) and issubclass(cls, BaseGenerator)):
                    errors.append(f"generator '{kind}' path '{path}' must subclass BaseGenerator")
            except (ImportError, AttributeError, ValueError) as exc:
                errors.append(f"generator '{kind}' path '{path}': {exc}")

        for kind, path in manifest.targets.items():
            try:
                cls = load_class(path)
                if not (isinstance(cls, type) and issubclass(cls, BaseTarget)):
                    errors.append(f"target '{kind}' path '{path}' must subclass BaseTarget")
            except (ImportError, AttributeError, ValueError) as exc:
                errors.append(f"target '{kind}' path '{path}': {exc}")

        return errors

__init__()

Initialize an empty bundle registry.

Source code in src/secretzero/bundles/registry.py
def __init__(self) -> None:
    """Initialize an empty bundle registry."""
    self._bundles: dict[str, BundleManifest] = {}
    self._generator_classes: dict[str, type] = {}
    self._target_classes: dict[str, type] = {}
    self._provider_classes: dict[str, type] = {}

register_bundle(manifest)

Register all classes declared in a bundle manifest.

Classes that cannot be imported (e.g. missing optional dependency) are silently skipped for graceful degradation.

Parameters:

Name Type Description Default
manifest BundleManifest

The bundle manifest to register.

required
Source code in src/secretzero/bundles/registry.py
def register_bundle(self, manifest: BundleManifest) -> None:
    """Register all classes declared in a bundle manifest.

    Classes that cannot be imported (e.g. missing optional dependency)
    are silently skipped for graceful degradation.

    Args:
        manifest: The bundle manifest to register.
    """
    self._bundles[manifest.name] = manifest

    if manifest.provider_class:
        cls = load_class_safe(manifest.provider_class)
        if cls is not None:
            self._provider_classes[manifest.name] = cls

    for kind, path in manifest.generators.items():
        cls = load_class_safe(path)
        if cls is not None:
            self._generator_classes[kind] = cls

    for kind, path in manifest.targets.items():
        cls = load_class_safe(path)
        if cls is not None:
            self._target_classes[kind] = cls

register_generator(kind, cls)

Directly register a generator class by kind.

Parameters:

Name Type Description Default
kind str

Generator kind identifier (e.g. "random_password").

required
cls type

Generator class to register.

required
Source code in src/secretzero/bundles/registry.py
def register_generator(self, kind: str, cls: type) -> None:
    """Directly register a generator class by kind.

    Args:
        kind: Generator kind identifier (e.g. ``"random_password"``).
        cls: Generator class to register.
    """
    self._generator_classes[kind] = cls

register_target(kind, cls)

Directly register a target class by kind.

Parameters:

Name Type Description Default
kind str

Target kind identifier (e.g. "file").

required
cls type

Target class to register.

required
Source code in src/secretzero/bundles/registry.py
def register_target(self, kind: str, cls: type) -> None:
    """Directly register a target class by kind.

    Args:
        kind: Target kind identifier (e.g. ``"file"``).
        cls: Target class to register.
    """
    self._target_classes[kind] = cls

register_provider(kind, cls)

Directly register a provider class by kind.

Parameters:

Name Type Description Default
kind str

Provider kind identifier (e.g. "aws").

required
cls type

Provider class to register.

required
Source code in src/secretzero/bundles/registry.py
def register_provider(self, kind: str, cls: type) -> None:
    """Directly register a provider class by kind.

    Args:
        kind: Provider kind identifier (e.g. ``"aws"``).
        cls: Provider class to register.
    """
    self._provider_classes[kind] = cls

discover_and_register()

Auto-discover installed bundles via Python entry_points.

Iterates over all packages that have registered an entry point under the "secretzero.providers" group. Each entry point value must be a :class:BundleManifest instance; others are silently skipped.

Source code in src/secretzero/bundles/registry.py
def discover_and_register(self) -> None:
    """Auto-discover installed bundles via Python ``entry_points``.

    Iterates over all packages that have registered an entry point
    under the ``"secretzero.providers"`` group.  Each entry point
    value must be a :class:`BundleManifest` instance; others are
    silently skipped.
    """
    for ep in importlib.metadata.entry_points(group="secretzero.providers"):
        try:
            manifest = ep.load()
            if isinstance(manifest, BundleManifest):
                self.register_bundle(manifest)
        except Exception:
            pass  # graceful degradation: never crash on bad bundles

get_generator_class(kind)

Return the generator class for kind, or None if unknown.

Parameters:

Name Type Description Default
kind str

Generator kind string (e.g. "random_password").

required

Returns:

Type Description
type | None

Generator class or None.

Source code in src/secretzero/bundles/registry.py
def get_generator_class(self, kind: str) -> type | None:
    """Return the generator class for *kind*, or ``None`` if unknown.

    Args:
        kind: Generator kind string (e.g. ``"random_password"``).

    Returns:
        Generator class or ``None``.
    """
    return self._generator_classes.get(kind)

get_target_class(kind)

Return the target class for kind, or None if unknown.

Parameters:

Name Type Description Default
kind str

Target kind string (e.g. "github_secret").

required

Returns:

Type Description
type | None

Target class or None.

Source code in src/secretzero/bundles/registry.py
def get_target_class(self, kind: str) -> type | None:
    """Return the target class for *kind*, or ``None`` if unknown.

    Args:
        kind: Target kind string (e.g. ``"github_secret"``).

    Returns:
        Target class or ``None``.
    """
    return self._target_classes.get(kind)

get_provider_class(kind)

Return the provider class for kind, or None if unknown.

Parameters:

Name Type Description Default
kind str

Provider kind string (e.g. "aws").

required

Returns:

Type Description
type | None

Provider class or None.

Source code in src/secretzero/bundles/registry.py
def get_provider_class(self, kind: str) -> type | None:
    """Return the provider class for *kind*, or ``None`` if unknown.

    Args:
        kind: Provider kind string (e.g. ``"aws"``).

    Returns:
        Provider class or ``None``.
    """
    return self._provider_classes.get(kind)

list_bundles()

Return a sorted list of all registered bundle names.

Returns:

Type Description
list[str]

Sorted list of bundle name strings.

Source code in src/secretzero/bundles/registry.py
def list_bundles(self) -> list[str]:
    """Return a sorted list of all registered bundle names.

    Returns:
        Sorted list of bundle name strings.
    """
    return sorted(self._bundles.keys())

list_generator_kinds()

Return a sorted list of all registered generator kind strings.

Returns:

Type Description
list[str]

Sorted list of generator kind strings.

Source code in src/secretzero/bundles/registry.py
def list_generator_kinds(self) -> list[str]:
    """Return a sorted list of all registered generator kind strings.

    Returns:
        Sorted list of generator kind strings.
    """
    return sorted(self._generator_classes.keys())

list_target_kinds()

Return a sorted list of all registered target kind strings.

Returns:

Type Description
list[str]

Sorted list of target kind strings.

Source code in src/secretzero/bundles/registry.py
def list_target_kinds(self) -> list[str]:
    """Return a sorted list of all registered target kind strings.

    Returns:
        Sorted list of target kind strings.
    """
    return sorted(self._target_classes.keys())

list_provider_kinds()

Return a sorted list of all registered provider kind strings.

Returns:

Type Description
list[str]

Sorted list of provider kind strings.

Source code in src/secretzero/bundles/registry.py
def list_provider_kinds(self) -> list[str]:
    """Return a sorted list of all registered provider kind strings.

    Returns:
        Sorted list of provider kind strings.
    """
    return sorted(self._provider_classes.keys())

get_bundle(name)

Return the manifest for a registered bundle, or None.

Parameters:

Name Type Description Default
name str

Bundle name.

required

Returns:

Type Description
BundleManifest | None

BundleManifest or None.

Source code in src/secretzero/bundles/registry.py
def get_bundle(self, name: str) -> BundleManifest | None:
    """Return the manifest for a registered bundle, or ``None``.

    Args:
        name: Bundle name.

    Returns:
        BundleManifest or ``None``.
    """
    return self._bundles.get(name)

validate_bundle_manifest(manifest)

Validate that all dotted paths in a manifest can be resolved.

Checks that each declared class path is importable, inherits from the appropriate base class, and is callable.

Parameters:

Name Type Description Default
manifest BundleManifest

The manifest to validate.

required

Returns:

Type Description
list[str]

List of error strings. An empty list means the manifest is valid.

Source code in src/secretzero/bundles/registry.py
def validate_bundle_manifest(self, manifest: BundleManifest) -> list[str]:
    """Validate that all dotted paths in a manifest can be resolved.

    Checks that each declared class path is importable, inherits from
    the appropriate base class, and is callable.

    Args:
        manifest: The manifest to validate.

    Returns:
        List of error strings.  An empty list means the manifest is valid.
    """
    from secretzero.bundles.loader import load_class
    from secretzero.generators.base import BaseGenerator
    from secretzero.providers.base import BaseProvider
    from secretzero.targets.base import BaseTarget

    errors: list[str] = []

    if manifest.provider_class:
        try:
            cls = load_class(manifest.provider_class)
            if not (isinstance(cls, type) and issubclass(cls, BaseProvider)):
                errors.append(
                    f"provider_class '{manifest.provider_class}' must subclass BaseProvider"
                )
        except (ImportError, AttributeError, ValueError) as exc:
            errors.append(f"provider_class '{manifest.provider_class}': {exc}")

    for kind, path in manifest.generators.items():
        try:
            cls = load_class(path)
            if not (isinstance(cls, type) and issubclass(cls, BaseGenerator)):
                errors.append(f"generator '{kind}' path '{path}' must subclass BaseGenerator")
        except (ImportError, AttributeError, ValueError) as exc:
            errors.append(f"generator '{kind}' path '{path}': {exc}")

    for kind, path in manifest.targets.items():
        try:
            cls = load_class(path)
            if not (isinstance(cls, type) and issubclass(cls, BaseTarget)):
                errors.append(f"target '{kind}' path '{path}' must subclass BaseTarget")
        except (ImportError, AttributeError, ValueError) as exc:
            errors.append(f"target '{kind}' path '{path}': {exc}")

    return errors

Module-level functions

get_bundle_registry()

Return the global :class:BundleRegistry singleton.

On first call the registry is populated with all built-in generators, targets, and providers, then third-party bundles discovered via entry_points are registered.

Returns:

Type Description
BundleRegistry

Global BundleRegistry instance.

Source code in src/secretzero/bundles/registry.py
def get_bundle_registry() -> BundleRegistry:
    """Return the global :class:`BundleRegistry` singleton.

    On first call the registry is populated with all built-in generators,
    targets, and providers, then third-party bundles discovered via
    ``entry_points`` are registered.

    Returns:
        Global BundleRegistry instance.
    """
    global _bundle_registry
    if _bundle_registry is None:
        _bundle_registry = BundleRegistry()
        _register_builtin_generators(_bundle_registry)
        _register_builtin_targets(_bundle_registry)
        _register_builtin_providers(_bundle_registry)
        _register_builtin_bundles(_bundle_registry)
        _bundle_registry.discover_and_register()
    return _bundle_registry

discover_bundles()

Discover all installed provider bundles via entry_points.

Returns:

Type Description
list[BundleManifest]

List of :class:BundleManifest instances found on the system.

Source code in src/secretzero/bundles/registry.py
def discover_bundles() -> list[BundleManifest]:
    """Discover all installed provider bundles via ``entry_points``.

    Returns:
        List of :class:`BundleManifest` instances found on the system.
    """
    bundles: list[BundleManifest] = []
    for ep in importlib.metadata.entry_points(group="secretzero.providers"):
        try:
            manifest = ep.load()
            if isinstance(manifest, BundleManifest):
                bundles.append(manifest)
        except Exception:
            pass
    return bundles

reset_bundle_registry()

Reset the global bundle registry singleton (for testing only).

After calling this, the next call to :func:get_bundle_registry will create a fresh registry and re-run discovery.

Source code in src/secretzero/bundles/registry.py
def reset_bundle_registry() -> None:
    """Reset the global bundle registry singleton (for testing only).

    After calling this, the next call to :func:`get_bundle_registry` will
    create a fresh registry and re-run discovery.
    """
    global _bundle_registry
    _bundle_registry = None

Class Loader

load_class(dotted_path)

Load a class from a dotted path string.

The path format is 'module.submodule:ClassName', where the colon separates the importable module path from the attribute name.

Parameters:

Name Type Description Default
dotted_path str

Dotted path in 'module.path:ClassName' format.

required

Returns:

Type Description
type

The class referenced by the path.

Raises:

Type Description
ValueError

If the path format is invalid (no colon separator).

ImportError

If the module cannot be imported.

AttributeError

If the class cannot be found in the module.

Example

cls = load_class("secretzero.generators.static:StaticGenerator") cls.name 'StaticGenerator'

Source code in src/secretzero/bundles/loader.py
def load_class(dotted_path: str) -> type:
    """Load a class from a dotted path string.

    The path format is ``'module.submodule:ClassName'``, where the colon
    separates the importable module path from the attribute name.

    Args:
        dotted_path: Dotted path in ``'module.path:ClassName'`` format.

    Returns:
        The class referenced by the path.

    Raises:
        ValueError: If the path format is invalid (no colon separator).
        ImportError: If the module cannot be imported.
        AttributeError: If the class cannot be found in the module.

    Example:
        >>> cls = load_class("secretzero.generators.static:StaticGenerator")
        >>> cls.__name__
        'StaticGenerator'
    """
    if ":" not in dotted_path:
        raise ValueError(
            f"Invalid dotted path '{dotted_path}': expected 'module.path:ClassName' format"
        )

    module_path, class_name = dotted_path.rsplit(":", 1)
    module = importlib.import_module(module_path)
    cls: type = getattr(module, class_name)
    return cls

load_class_safe(dotted_path)

Load a class from a dotted path string, returning None on failure.

Convenience wrapper around :func:load_class that catches all errors and returns None instead of raising, enabling graceful degradation.

Parameters:

Name Type Description Default
dotted_path str

Dotted path in 'module.path:ClassName' format.

required

Returns:

Type Description
type[Any] | None

The class if loading succeeded, or None on any error.

Source code in src/secretzero/bundles/loader.py
def load_class_safe(dotted_path: str) -> type[Any] | None:
    """Load a class from a dotted path string, returning None on failure.

    Convenience wrapper around :func:`load_class` that catches all errors
    and returns ``None`` instead of raising, enabling graceful degradation.

    Args:
        dotted_path: Dotted path in ``'module.path:ClassName'`` format.

    Returns:
        The class if loading succeeded, or ``None`` on any error.
    """
    try:
        return load_class(dotted_path)
    except (ImportError, AttributeError, ValueError, Exception):
        return None

Base Classes

These are the abstract base classes that bundle implementations must subclass.

BaseProvider

BaseProvider

Bases: IProviderWithCapabilities

Base class for all providers with capability support.

Source code in src/secretzero/providers/base.py
class BaseProvider(IProviderWithCapabilities):
    """Base class for all providers with capability support."""

    #: Human-readable name shown in CLI listings (e.g. "Amazon Web Services").
    display_name: str = ""

    #: Short description shown in CLI listings.
    description: str = ""

    #: ``(import_name, pip_install_name)`` for the required third-party
    #: package, e.g. ``("boto3", "secretzero[aws]")``.  ``None`` if the
    #: provider has no extra dependencies.
    required_package: tuple[str, str] | None = None

    #: The :class:`ProviderAuth` subclass used by this provider.
    #: Subclasses should override this so CLI/tooling can inspect
    #: auth-level metadata (e.g. ``ENV_TOKEN``) without instantiation.
    auth_class: type[ProviderAuth] = ProviderAuth

    #: Supported authentication method names and descriptions, e.g.
    #: ``{"token": "Use a personal access token", "ambient": "SDK chain"}``.
    auth_methods: dict[str, str] = {}

    #: Configuration options shown in CLI help, e.g.
    #: ``{"region": "AWS region (default: us-east-1)"}``.
    config_options: dict[str, str] = {}

    #: Example YAML snippet shown in ``secretzero providers --provider <kind>``.
    config_example: str = ""

    #: Mapping of target kind → detail dict for CLI display.
    #: Each value has ``description``, ``config`` (dict[str, str]), and ``example`` (str).
    target_details: dict[str, dict[str, Any]] = {}

    @classmethod
    def get_provider_detail(cls) -> dict[str, Any]:
        """Return a self-describing detail dict used by CLI ``providers`` commands.

        The returned dict has keys ``description``, ``auth_methods``,
        ``config``, ``example``, ``target_details`` — all sourced from
        class-level attributes so bundles self-register their docs.

        Returns:
            Provider detail dictionary.
        """
        return {
            "description": cls.display_name or cls.description,
            "auth_methods": dict(cls.auth_methods),
            "config": dict(cls.config_options),
            "example": cls.config_example,
            "target_details": dict(cls.target_details),
        }

    def __init__(
        self,
        name: str,
        config: dict[str, Any] | None = None,
        auth: ProviderAuth | None = None,
    ):
        """Initialize provider.

        Args:
            name: Provider name
            config: Provider configuration
            auth: Provider authentication instance
        """
        self.name = name
        self.config = config or {}
        self.auth = auth
        self._authenticated = False

    @property
    @abstractmethod
    def provider_kind(self) -> str:
        """Return provider type identifier.

        Returns:
            Provider kind string (e.g., 'vault', 'aws', 'github')
        """
        pass

    @abstractmethod
    def test_connection(self) -> tuple[bool, str | None]:
        """Test provider connectivity.

        Returns:
            Tuple of (success: bool, error_message: Optional[str])
        """
        pass

    def authenticate(self) -> bool:
        """Authenticate with the provider.

        Returns:
            True if authentication successful, False otherwise
        """
        if self.auth:
            self._authenticated = self.auth.authenticate()
            return self._authenticated
        return False

    def is_authenticated(self) -> bool:
        """Check if provider is authenticated.

        Returns:
            True if authenticated, False otherwise
        """
        if self.auth:
            return self.auth.is_authenticated()
        return self._authenticated

    @abstractmethod
    def get_supported_targets(self) -> list[str]:
        """Get list of supported target types for this provider.

        Returns:
            List of target type names
        """
        pass

    @classmethod
    def get_capabilities(cls) -> ProviderCapabilities:
        """Declare all capabilities this provider offers.

        Default implementation uses introspection to find methods starting with
        'generate_', 'retrieve_', 'store_', 'rotate_', or 'delete_'.

        Override this method for custom capability declarations.

        Returns:
            ProviderCapabilities describing all methods and their signatures
        """
        capabilities = []

        # Find all methods with capability prefixes
        capability_prefixes = {
            "generate": CapabilityType.GENERATE,
            "retrieve": CapabilityType.RETRIEVE,
            "store": CapabilityType.STORE,
            "rotate": CapabilityType.ROTATE,
            "delete": CapabilityType.DELETE,
        }

        for method_name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
            if method_name.startswith("_"):
                continue  # Skip private methods

            # Check if method matches a capability prefix
            capability_type = None
            for prefix, cap_type in capability_prefixes.items():
                if method_name.startswith(f"{prefix}_"):
                    capability_type = cap_type
                    break

            if capability_type is None:
                continue  # Not a capability method

            try:
                sig = inspect.signature(method)
                type_hints = get_type_hints(method)

                # Build parameter schema
                params = {}
                for param_name, param in sig.parameters.items():
                    if param_name in ("self", "cls"):
                        continue

                    param_type = type_hints.get(param_name, Any)
                    param_type_str = str(param_type).replace("typing.", "")

                    params[param_name] = ParameterSchema(
                        type=param_type_str,
                        required=param.default == inspect.Parameter.empty,
                        default=None if param.default == inspect.Parameter.empty else param.default,
                        description=f"Parameter {param_name}",
                    )

                return_type = type_hints.get("return", Any)
                return_type_str = str(return_type).replace("typing.", "")

                method_sig = MethodSignature(
                    name=method_name,
                    description=method.__doc__ or f"{capability_type.value.capitalize()} operation",
                    return_type=return_type_str,
                    parameters=params,
                )

                capabilities.append(
                    Capability(
                        capability_type=capability_type,
                        method=method_sig,
                        requires_auth=True,
                        supported_targets=[],  # Empty means all targets
                    )
                )
            except Exception:
                # Skip methods that fail introspection
                continue

        # Get provider kind from instance property or class name
        # Try to instantiate temporarily to get provider_kind (if it doesn't require args)
        provider_kind = cls.__name__.lower().replace("provider", "").strip()
        try:
            # Try to get from a dummy instance (if class can be instantiated without args)
            # This is just for introspection, not for actual use
            pass  # Use class name for now since providers need auth/config
        except Exception:
            pass

        return ProviderCapabilities(
            provider_kind=provider_kind, version="1.0", capabilities=capabilities
        )

    def list_available_methods(self) -> list[str]:
        """List all callable capability methods on this provider instance.

        Returns:
            List of method names available after authentication
        """
        methods = []
        capability_prefixes = ["generate_", "retrieve_", "store_", "rotate_", "delete_"]

        for method_name in dir(self):
            if method_name.startswith("_"):
                continue
            method = getattr(self, method_name, None)
            if callable(method):
                if any(method_name.startswith(prefix) for prefix in capability_prefixes):
                    methods.append(method_name)

        return methods

    def get_method_schema(self, method_name: str) -> MethodSignature:
        """Get schema for a specific method.

        Args:
            method_name: Name of method to inspect

        Returns:
            MethodSignature with parameter and return types

        Raises:
            ValueError: If method not found
        """
        capabilities = self.get_capabilities()
        capability = capabilities.get_capability(method_name)

        if capability is None:
            raise ValueError(f"Method '{method_name}' not found in {self.provider_kind} provider")

        return capability.method

    def get_token_info(self) -> dict[str, Any]:
        """Return information about the current authentication token.

        Delegates to the underlying :class:`ProviderAuth` instance. Providers
        whose auth class implements ``get_token_info`` will return meaningful
        data; others will raise :class:`NotImplementedError`.

        Returns:
            Dictionary with token details (see :meth:`ProviderAuth.get_token_info`).

        Raises:
            RuntimeError: If no authentication is configured.
            NotImplementedError: If the auth class does not support introspection.
        """
        if not self.auth:
            raise RuntimeError("No authentication configured")
        return self.auth.get_token_info()

    @classmethod
    def get_scope_descriptions(cls) -> dict[str, str]:
        """Return scope/permission descriptions for this provider's auth layer.

        Returns:
            Mapping of scope name to human-readable description.
        """
        return {}

provider_kind abstractmethod property

Return provider type identifier.

Returns:

Type Description
str

Provider kind string (e.g., 'vault', 'aws', 'github')

test_connection() abstractmethod

Test provider connectivity.

Returns:

Type Description
tuple[bool, str | None]

Tuple of (success: bool, error_message: Optional[str])

Source code in src/secretzero/providers/base.py
@abstractmethod
def test_connection(self) -> tuple[bool, str | None]:
    """Test provider connectivity.

    Returns:
        Tuple of (success: bool, error_message: Optional[str])
    """
    pass

authenticate()

Authenticate with the provider.

Returns:

Type Description
bool

True if authentication successful, False otherwise

Source code in src/secretzero/providers/base.py
def authenticate(self) -> bool:
    """Authenticate with the provider.

    Returns:
        True if authentication successful, False otherwise
    """
    if self.auth:
        self._authenticated = self.auth.authenticate()
        return self._authenticated
    return False

is_authenticated()

Check if provider is authenticated.

Returns:

Type Description
bool

True if authenticated, False otherwise

Source code in src/secretzero/providers/base.py
def is_authenticated(self) -> bool:
    """Check if provider is authenticated.

    Returns:
        True if authenticated, False otherwise
    """
    if self.auth:
        return self.auth.is_authenticated()
    return self._authenticated

get_supported_targets() abstractmethod

Get list of supported target types for this provider.

Returns:

Type Description
list[str]

List of target type names

Source code in src/secretzero/providers/base.py
@abstractmethod
def get_supported_targets(self) -> list[str]:
    """Get list of supported target types for this provider.

    Returns:
        List of target type names
    """
    pass

get_capabilities() classmethod

Declare all capabilities this provider offers.

Default implementation uses introspection to find methods starting with 'generate_', 'retrieve_', 'store_', 'rotate_', or 'delete_'.

Override this method for custom capability declarations.

Returns:

Type Description
ProviderCapabilities

ProviderCapabilities describing all methods and their signatures

Source code in src/secretzero/providers/base.py
@classmethod
def get_capabilities(cls) -> ProviderCapabilities:
    """Declare all capabilities this provider offers.

    Default implementation uses introspection to find methods starting with
    'generate_', 'retrieve_', 'store_', 'rotate_', or 'delete_'.

    Override this method for custom capability declarations.

    Returns:
        ProviderCapabilities describing all methods and their signatures
    """
    capabilities = []

    # Find all methods with capability prefixes
    capability_prefixes = {
        "generate": CapabilityType.GENERATE,
        "retrieve": CapabilityType.RETRIEVE,
        "store": CapabilityType.STORE,
        "rotate": CapabilityType.ROTATE,
        "delete": CapabilityType.DELETE,
    }

    for method_name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
        if method_name.startswith("_"):
            continue  # Skip private methods

        # Check if method matches a capability prefix
        capability_type = None
        for prefix, cap_type in capability_prefixes.items():
            if method_name.startswith(f"{prefix}_"):
                capability_type = cap_type
                break

        if capability_type is None:
            continue  # Not a capability method

        try:
            sig = inspect.signature(method)
            type_hints = get_type_hints(method)

            # Build parameter schema
            params = {}
            for param_name, param in sig.parameters.items():
                if param_name in ("self", "cls"):
                    continue

                param_type = type_hints.get(param_name, Any)
                param_type_str = str(param_type).replace("typing.", "")

                params[param_name] = ParameterSchema(
                    type=param_type_str,
                    required=param.default == inspect.Parameter.empty,
                    default=None if param.default == inspect.Parameter.empty else param.default,
                    description=f"Parameter {param_name}",
                )

            return_type = type_hints.get("return", Any)
            return_type_str = str(return_type).replace("typing.", "")

            method_sig = MethodSignature(
                name=method_name,
                description=method.__doc__ or f"{capability_type.value.capitalize()} operation",
                return_type=return_type_str,
                parameters=params,
            )

            capabilities.append(
                Capability(
                    capability_type=capability_type,
                    method=method_sig,
                    requires_auth=True,
                    supported_targets=[],  # Empty means all targets
                )
            )
        except Exception:
            # Skip methods that fail introspection
            continue

    # Get provider kind from instance property or class name
    # Try to instantiate temporarily to get provider_kind (if it doesn't require args)
    provider_kind = cls.__name__.lower().replace("provider", "").strip()
    try:
        # Try to get from a dummy instance (if class can be instantiated without args)
        # This is just for introspection, not for actual use
        pass  # Use class name for now since providers need auth/config
    except Exception:
        pass

    return ProviderCapabilities(
        provider_kind=provider_kind, version="1.0", capabilities=capabilities
    )

get_provider_detail() classmethod

Return a self-describing detail dict used by CLI providers commands.

The returned dict has keys description, auth_methods, config, example, target_details — all sourced from class-level attributes so bundles self-register their docs.

Returns:

Type Description
dict[str, Any]

Provider detail dictionary.

Source code in src/secretzero/providers/base.py
@classmethod
def get_provider_detail(cls) -> dict[str, Any]:
    """Return a self-describing detail dict used by CLI ``providers`` commands.

    The returned dict has keys ``description``, ``auth_methods``,
    ``config``, ``example``, ``target_details`` — all sourced from
    class-level attributes so bundles self-register their docs.

    Returns:
        Provider detail dictionary.
    """
    return {
        "description": cls.display_name or cls.description,
        "auth_methods": dict(cls.auth_methods),
        "config": dict(cls.config_options),
        "example": cls.config_example,
        "target_details": dict(cls.target_details),
    }

ProviderAuth

ProviderAuth

Bases: ABC

Base class for provider authentication.

Source code in src/secretzero/providers/base.py
class ProviderAuth(ABC):
    """Base class for provider authentication."""

    #: Environment variable that carries the authentication token.
    #: Subclasses should override (e.g. ``ENV_TOKEN = "GITHUB_TOKEN"``).
    ENV_TOKEN: str = ""

    def __init__(self, config: dict[str, Any] | None = None):
        """Initialize authentication with configuration.

        Args:
            config: Authentication configuration dictionary
        """
        self.config = config or {}

    @abstractmethod
    def authenticate(self) -> bool:
        """Authenticate with the provider.

        Returns:
            True if authentication successful, False otherwise
        """
        pass

    @abstractmethod
    def is_authenticated(self) -> bool:
        """Check if currently authenticated.

        Returns:
            True if authenticated, False otherwise
        """
        pass

    def get_client(self) -> Any:
        """Get authenticated client for the provider.

        Returns:
            Authenticated client instance or None
        """
        return None

    def get_token_info(self) -> dict[str, Any]:
        """Return information about the current authentication token.

        Providers that support token introspection should override this method
        to return details such as user identity, scopes/permissions, and token
        type.

        Returns:
            Dictionary with at least:
                - user: Identity associated with the token
                - scopes: List of permission scopes granted
                - token_type: Kind of token (e.g. 'PAT', 'OAuth')

        Raises:
            NotImplementedError: If the provider does not support token introspection.
        """
        raise NotImplementedError(f"{type(self).__name__} does not support token introspection")

    @classmethod
    def get_scope_descriptions(cls) -> dict[str, str]:
        """Return a mapping of scope/permission names to human-readable descriptions.

        Providers that expose OAuth-style scopes should override this method.

        Returns:
            Dictionary mapping scope name to description string.
        """
        return {}

authenticate() abstractmethod

Authenticate with the provider.

Returns:

Type Description
bool

True if authentication successful, False otherwise

Source code in src/secretzero/providers/base.py
@abstractmethod
def authenticate(self) -> bool:
    """Authenticate with the provider.

    Returns:
        True if authentication successful, False otherwise
    """
    pass

is_authenticated() abstractmethod

Check if currently authenticated.

Returns:

Type Description
bool

True if authenticated, False otherwise

Source code in src/secretzero/providers/base.py
@abstractmethod
def is_authenticated(self) -> bool:
    """Check if currently authenticated.

    Returns:
        True if authenticated, False otherwise
    """
    pass

get_client()

Get authenticated client for the provider.

Returns:

Type Description
Any

Authenticated client instance or None

Source code in src/secretzero/providers/base.py
def get_client(self) -> Any:
    """Get authenticated client for the provider.

    Returns:
        Authenticated client instance or None
    """
    return None

get_token_info()

Return information about the current authentication token.

Providers that support token introspection should override this method to return details such as user identity, scopes/permissions, and token type.

Returns:

Type Description
dict[str, Any]

Dictionary with at least: - user: Identity associated with the token - scopes: List of permission scopes granted - token_type: Kind of token (e.g. 'PAT', 'OAuth')

Raises:

Type Description
NotImplementedError

If the provider does not support token introspection.

Source code in src/secretzero/providers/base.py
def get_token_info(self) -> dict[str, Any]:
    """Return information about the current authentication token.

    Providers that support token introspection should override this method
    to return details such as user identity, scopes/permissions, and token
    type.

    Returns:
        Dictionary with at least:
            - user: Identity associated with the token
            - scopes: List of permission scopes granted
            - token_type: Kind of token (e.g. 'PAT', 'OAuth')

    Raises:
        NotImplementedError: If the provider does not support token introspection.
    """
    raise NotImplementedError(f"{type(self).__name__} does not support token introspection")

BaseGenerator

BaseGenerator

Bases: ABC

Abstract base class for secret generators.

Source code in src/secretzero/generators/base.py
class BaseGenerator(ABC):
    """Abstract base class for secret generators."""

    def __init__(self, config: dict[str, Any]) -> None:
        """Initialize generator with configuration.

        Args:
            config: Generator configuration dictionary
        """
        self.config = config
        self.field_description = None
        self.hide_input = False

    @abstractmethod
    def generate(self) -> str:
        """Generate a secret value.

        Returns:
            Generated secret value as a string
        """
        pass

    def generate_with_fallback(
        self, env_var_name: str | None = None, field_description: str | None = None
    ) -> str:
        """Generate a secret value with environment variable fallback.

        First checks for an environment variable, then falls back to generation.

        Args:
            env_var_name: Optional environment variable name to check first
            field_description: Optional field description for context in prompts

        Returns:
            Secret value from environment or generated
        """
        if field_description:
            self.field_description = field_description

        if env_var_name:
            env_value = os.environ.get(env_var_name)
            if env_value:
                return env_value

        return self.generate()

generate() abstractmethod

Generate a secret value.

Returns:

Type Description
str

Generated secret value as a string

Source code in src/secretzero/generators/base.py
@abstractmethod
def generate(self) -> str:
    """Generate a secret value.

    Returns:
        Generated secret value as a string
    """
    pass

generate_with_fallback(env_var_name=None, field_description=None)

Generate a secret value with environment variable fallback.

First checks for an environment variable, then falls back to generation.

Parameters:

Name Type Description Default
env_var_name str | None

Optional environment variable name to check first

None
field_description str | None

Optional field description for context in prompts

None

Returns:

Type Description
str

Secret value from environment or generated

Source code in src/secretzero/generators/base.py
def generate_with_fallback(
    self, env_var_name: str | None = None, field_description: str | None = None
) -> str:
    """Generate a secret value with environment variable fallback.

    First checks for an environment variable, then falls back to generation.

    Args:
        env_var_name: Optional environment variable name to check first
        field_description: Optional field description for context in prompts

    Returns:
        Secret value from environment or generated
    """
    if field_description:
        self.field_description = field_description

    if env_var_name:
        env_value = os.environ.get(env_var_name)
        if env_value:
            return env_value

    return self.generate()

BaseTarget

BaseTarget

Bases: ABC

Abstract base class for secret storage targets.

Source code in src/secretzero/targets/base.py
class BaseTarget(ABC):
    """Abstract base class for secret storage targets."""

    def __init__(
        self,
        provider: Any | None = None,
        config: dict[str, Any] | None = None,
    ) -> None:
        """Initialize target with configuration.

        Args:
            provider: Optional provider instance for targets that need credentials
            config: Target configuration dictionary
        """
        # Handle backward compatibility: if provider is a dict and config is None,
        # assume old calling convention where only config was passed
        if isinstance(provider, dict) and config is None:
            self.provider = None
            self.config = provider
        else:
            self.provider = provider
            self.config = config or {}

    @abstractmethod
    def store(self, secret_name: str, secret_value: str) -> bool:
        """Store a secret value in the target.

        Args:
            secret_name: Name/key of the secret
            secret_value: Value to store

        Returns:
            True if successful, False otherwise
        """
        pass

    @abstractmethod
    def retrieve(self, secret_name: str) -> str | None:
        """Retrieve a secret value from the target.

        Args:
            secret_name: Name/key of the secret

        Returns:
            Secret value if found, None otherwise
        """
        pass

    def validate(self) -> tuple[bool, str | None]:
        """Validate that the target is accessible and writable.

        Returns:
            Tuple of (success, error_message)
            If successful, error_message is None.
            If failed, error_message describes the issue.
        """
        # Default implementation assumes target is valid
        # Subclasses should override to provide specific validation
        return True, None

store(secret_name, secret_value) abstractmethod

Store a secret value in the target.

Parameters:

Name Type Description Default
secret_name str

Name/key of the secret

required
secret_value str

Value to store

required

Returns:

Type Description
bool

True if successful, False otherwise

Source code in src/secretzero/targets/base.py
@abstractmethod
def store(self, secret_name: str, secret_value: str) -> bool:
    """Store a secret value in the target.

    Args:
        secret_name: Name/key of the secret
        secret_value: Value to store

    Returns:
        True if successful, False otherwise
    """
    pass

retrieve(secret_name) abstractmethod

Retrieve a secret value from the target.

Parameters:

Name Type Description Default
secret_name str

Name/key of the secret

required

Returns:

Type Description
str | None

Secret value if found, None otherwise

Source code in src/secretzero/targets/base.py
@abstractmethod
def retrieve(self, secret_name: str) -> str | None:
    """Retrieve a secret value from the target.

    Args:
        secret_name: Name/key of the secret

    Returns:
        Secret value if found, None otherwise
    """
    pass

validate()

Validate that the target is accessible and writable.

Returns:

Type Description
bool

Tuple of (success, error_message)

str | None

If successful, error_message is None.

tuple[bool, str | None]

If failed, error_message describes the issue.

Source code in src/secretzero/targets/base.py
def validate(self) -> tuple[bool, str | None]:
    """Validate that the target is accessible and writable.

    Returns:
        Tuple of (success, error_message)
        If successful, error_message is None.
        If failed, error_message describes the issue.
    """
    # Default implementation assumes target is valid
    # Subclasses should override to provide specific validation
    return True, None

Dotted Path Format

All class references in a BundleManifest use the module.path:ClassName format:

secretzero_mycloud.provider:MyCloudProvider
│                  │        │
│                  │        └── Attribute name within the module
│                  └── Submodule
└── Top-level package

The colon (:) separates the importable module path from the class attribute. This is the same format used by Python entry_points.

Entry Points Group

Bundles register under the secretzero.providers entry-point group:

# pyproject.toml
[project.entry-points."secretzero.providers"]
mycloud = "secretzero_mycloud:BUNDLE_MANIFEST"

The entry-point name (left side) is informational. The entry-point value (right side) must resolve to a BundleManifest instance.

Built-in Bundle Manifests

Each built-in provider exposes a _get_bundle_manifest() factory function that returns its BundleManifest. These are registered by _register_builtin_bundles() during registry initialization rather than via entry_points.

Provider Manifest factory
AWS secretzero.providers.aws:_get_bundle_manifest
Azure secretzero.providers.azure:_get_bundle_manifest
Vault secretzero.providers.vault:_get_bundle_manifest
GitHub secretzero.providers.github:_get_bundle_manifest
GitLab secretzero.providers.gitlab:_get_bundle_manifest
Jenkins secretzero.providers.jenkins:_get_bundle_manifest
Kubernetes secretzero.providers.kubernetes:_get_bundle_manifest
Ansible Vault secretzero.providers.ansible_vault:_get_bundle_manifest
Infisical secretzero.providers.infisical:_get_bundle_manifest