Skip to content

API Reference: Validators

Use the registry functions below to discover and register validators. For a working extension, follow Custom Validators; for built-in behavior and arguments, use the validator catalog.

Registry

certmonitor.validators

VALIDATORS module-attribute

VALIDATORS = {'expiration': ExpirationValidator(), 'hostname': HostnameValidator(), 'key_info': KeyInfoValidator(), 'subject_alt_names': SubjectAltNamesValidator(), 'root_certificate': RootCertificateValidator(), 'sensitive_date': SensitiveDateValidator(), 'tls_version': TLSVersionValidator(), 'weak_cipher': WeakCipherValidator(), 'chain': ChainValidator(), 'pq_key_exchange': PqKeyExchangeValidator(), 'pq_chain': PqChainValidator(), 'pq_signature': PqSignatureValidator(), 'revocation': RevocationValidator()}

get_enabled_validators

get_enabled_validators() -> list

Get enabled validators from configuration.

Returns:

Name Type Description
list list

A list of enabled validator names.

Source code in certmonitor/validators/__init__.py
def get_enabled_validators() -> list:
    """
    Get enabled validators from configuration.

    Returns:
        list: A list of enabled validator names.
    """
    from ..config import ENABLED_VALIDATORS

    return ENABLED_VALIDATORS

list_validators

list_validators() -> list

Lists all currently registered validators.

Returns:

Name Type Description
list list

A list of validator names.

Source code in certmonitor/validators/__init__.py
def list_validators() -> list:
    """
    Lists all currently registered validators.

    Returns:
        list: A list of validator names.
    """
    return list(VALIDATORS.keys())

register_validator

register_validator(validator_instance: Any) -> None

Register a custom validator instance with the system.

Parameters:

Name Type Description Default
validator_instance BaseValidator

An instance of a validator class that inherits from BaseValidator.

required
Source code in certmonitor/validators/__init__.py
def register_validator(validator_instance: Any) -> None:
    """
    Register a custom validator instance with the system.

    Args:
        validator_instance (BaseValidator): An instance of a validator class
                                            that inherits from BaseValidator.
    """
    name = validator_instance.name
    VALIDATORS[name] = validator_instance

The result envelope

Every validator returns the envelope described below, and validate() adds status and code. Validator-specific data fields are documented on each page of the validator catalog.

certmonitor.validators.results

The standard validator result envelope.

Every validator returns a plain dict (JSON-serializable, accessed with result["is_valid"]). These TypedDict classes declare the schema of that dict without changing its runtime type, so mypy can enforce the contract while consumers keep working with ordinary dicts.

The envelope contract:

Key Type Rule
is_valid bool Always present, strict bool, never None in conforming validators.
reason str Present if and only if is_valid is False. One human-readable sentence stating the primary cause.
warnings list[str] Optional. Non-fatal findings.
error str Optional. Machine-readable error class on operational failures (connection refused, probe failed, and so on).
message str Optional. Human-readable detail accompanying error.

All other keys are validator-specific data fields: snake_case, documented on the validator's docs page, with behavior changes called out in the migration guide. The reserved keys above are never reused for data.

The dispatcher adds status (pass/warn/fail/error/unsupported) and code (<validator>.<status>). Individual validators may provide a status when the result is operationally inconclusive or unsupported.

Operational failures are still results: a validator whose data source cannot be fetched reports is_valid: False with a reason (plus error/message where a machine-readable class helps), it is never silently omitted from validate() output.

A validator declares its full shape by extending ValidationResult with its data fields (see pq_signature.py for an example):

class MyResult(ValidationResult, total=False):
    my_data_field: str
Note

typing.NotRequired is only available on Python 3.11+, and the project has a zero-dependency rule (no typing_extensions), so on the 3.10 floor we use the two-class required/optional split below.

ValidationResult

Bases: _ValidationResultBase

Standard validator result envelope (see module docstring).

is_valid is required; the optional keys below are reserved and may only carry envelope semantics. Validator-specific data fields are declared by extending this class with total=False.

code instance-attribute

code: str

error instance-attribute

error: str

message instance-attribute

message: str

reason instance-attribute

reason: str

status instance-attribute

status: str

warnings instance-attribute

warnings: list[str]

Base classes

Choose a certificate or cipher base according to the data your check consumes. User-configurable options must be keyword-only, annotated, and defaulted.

certmonitor.validators.base

Base classes for certmonitor validators.

Contributors writing a new validator should subclass BaseCertValidator (for validators that inspect certificate data) or BaseCipherValidator (for validators that inspect cipher suite data) and implement validate.

The first three positional parameters of validate are supplied by the dispatcher, the parsed cert or cipher data, the host, and the port. Any additional user-configurable arguments must be declared as keyword-only parameters, each with a type annotation and a default value. The class-level __init_subclass__ hook enforces this at import time, caches the discovered user parameters, and exposes them for dispatch and introspection.

BaseCertValidator

Bases: _ValidatorBase

Base class for validators that inspect parsed certificate data.

requires class-attribute

requires: tuple[str, ...] = ('cert_data',)

validator_type class-attribute instance-attribute

validator_type: str = 'cert'

validate

validate(cert_info: dict[str, Any], host: str, port: int) -> Mapping[str, Any]
Source code in certmonitor/validators/base.py
def validate(
    self, cert_info: dict[str, Any], host: str, port: int
) -> Mapping[str, Any]:
    # Default implementation, subclasses override.
    return None  # type: ignore[return-value]

BaseCipherValidator

Bases: _ValidatorBase

Base class for validators that inspect negotiated cipher suite data.

requires class-attribute

requires: tuple[str, ...] = ('cipher_info',)

validator_type class-attribute instance-attribute

validator_type: str = 'cipher'

validate

validate(cipher_info: dict[str, Any], host: str, port: int) -> Mapping[str, Any]
Source code in certmonitor/validators/base.py
def validate(
    self, cipher_info: dict[str, Any], host: str, port: int
) -> Mapping[str, Any]:
    # Default implementation, subclasses override.
    return None  # type: ignore[return-value]

BaseValidator

Bases: ABC

Abstract base class for certificate and cipher validators.

name abstractmethod property

name: str

Return the name used to register and look up this validator.

validate abstractmethod

validate(*args: Any, **kwargs: Any) -> Mapping[str, Any]

Run the validator and return a result dict.

The result must conform to the standard envelope, see certmonitor.validators.results.ValidationResult. The return type is Mapping (not Dict) so overrides may annotate a precise TypedDict; at runtime every result is a plain dict.

Source code in certmonitor/validators/base.py
@abstractmethod
def validate(self, *args: Any, **kwargs: Any) -> Mapping[str, Any]:
    """Run the validator and return a result dict.

    The result must conform to the standard envelope, see
    `certmonitor.validators.results.ValidationResult`. The
    return type is `Mapping` (not `Dict`) so overrides may
    annotate a precise `TypedDict`; at runtime every result is a
    plain dict.
    """