Skip to content

validator

trestle.core.validator ¤

Base class for all validators.

logger ¤

Classes¤

Validator (ABC) ¤

Validator base class.

Source code in trestle/core/validator.py
class Validator(ABC):
    """Validator base class."""

    def error_msg(self) -> Optional[str]:
        """Error message used to describe this validator."""
        # subclasses can override as needed
        return self.__doc__

    @abstractmethod
    def model_is_valid(
        self, model: TopLevelOscalModel, quiet: bool, trestle_root: Optional[pathlib.Path] = None
    ) -> bool:
        """
        Validate the model.

        args:
            model: An Oscal model that can be passed to the validator.
            quiet: Don't report msgs unless invalid.

        returns:
            Whether or not the model passed this validation test.
        """

    def validate(self, args: argparse.Namespace) -> int:
        """Perform the validation according to user options."""
        trestle_root = args.trestle_root  # trestle root is set via command line in args. Default is cwd.

        # validate by type - all of type or just specified by name
        if args.type:
            models = []
            if args.name:
                models = [args.name]
            else:
                models = ModelUtils.get_models_of_type(args.type, trestle_root)
            models_path = trestle_root / ModelUtils.model_type_to_model_dir(args.type)
            for m in models:
                model_path = models_path / m
                try:
                    _, _, model = ModelUtils.load_distributed(model_path, trestle_root)
                except TrestleError as e:
                    logger.warning(f'File load error {e}')
                    return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
                if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
                    logger.info(f'INVALID: Model {model_path} did not pass the {self.error_msg()}')
                    return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
                if not args.quiet:
                    logger.info(f'VALID: Model {model_path} passed the {self.error_msg()}')
            return CmdReturnCodes.SUCCESS.value

        # validate all
        if args.all:
            model_tups = ModelUtils.get_all_models(trestle_root)
            for mt in model_tups:

                model_dir = trestle_root / ModelUtils.model_type_to_model_dir(mt[0]) / mt[1]
                extension_type = trestle.common.file_utils.get_contextual_file_type(model_dir)
                model_path = model_dir / f'{mt[0]}{FileContentType.to_file_extension(extension_type)}'
                _, _, model = ModelUtils.load_distributed(model_path, trestle_root)
                if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
                    logger.info(f'INVALID: Model {model_path} did not pass the {self.error_msg()}')
                    return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
                if not args.quiet:
                    logger.info(f'VALID: Model {model_path} passed the {self.error_msg()}')
            return CmdReturnCodes.SUCCESS.value

        # validate file
        if args.file:
            file_path = trestle_root / args.file
            _, _, model = ModelUtils.load_distributed(file_path, trestle_root)
            if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
                logger.info(f'INVALID: Model {file_path} did not pass the {self.error_msg()}')
                return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
            if not args.quiet:
                logger.info(f'VALID: Model {file_path} passed the {self.error_msg()}')
        return CmdReturnCodes.SUCCESS.value
Methods¤
error_msg(self) ¤

Error message used to describe this validator.

Source code in trestle/core/validator.py
def error_msg(self) -> Optional[str]:
    """Error message used to describe this validator."""
    # subclasses can override as needed
    return self.__doc__
model_is_valid(self, model, quiet, trestle_root=None) ¤

Validate the model.

Parameters:

Name Type Description Default
model ~TopLevelOscalModel

An Oscal model that can be passed to the validator.

required
quiet bool

Don't report msgs unless invalid.

required

Returns:

Type Description
bool

Whether or not the model passed this validation test.

Source code in trestle/core/validator.py
@abstractmethod
def model_is_valid(
    self, model: TopLevelOscalModel, quiet: bool, trestle_root: Optional[pathlib.Path] = None
) -> bool:
    """
    Validate the model.

    args:
        model: An Oscal model that can be passed to the validator.
        quiet: Don't report msgs unless invalid.

    returns:
        Whether or not the model passed this validation test.
    """
validate(self, args) ¤

Perform the validation according to user options.

Source code in trestle/core/validator.py
def validate(self, args: argparse.Namespace) -> int:
    """Perform the validation according to user options."""
    trestle_root = args.trestle_root  # trestle root is set via command line in args. Default is cwd.

    # validate by type - all of type or just specified by name
    if args.type:
        models = []
        if args.name:
            models = [args.name]
        else:
            models = ModelUtils.get_models_of_type(args.type, trestle_root)
        models_path = trestle_root / ModelUtils.model_type_to_model_dir(args.type)
        for m in models:
            model_path = models_path / m
            try:
                _, _, model = ModelUtils.load_distributed(model_path, trestle_root)
            except TrestleError as e:
                logger.warning(f'File load error {e}')
                return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
            if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
                logger.info(f'INVALID: Model {model_path} did not pass the {self.error_msg()}')
                return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
            if not args.quiet:
                logger.info(f'VALID: Model {model_path} passed the {self.error_msg()}')
        return CmdReturnCodes.SUCCESS.value

    # validate all
    if args.all:
        model_tups = ModelUtils.get_all_models(trestle_root)
        for mt in model_tups:

            model_dir = trestle_root / ModelUtils.model_type_to_model_dir(mt[0]) / mt[1]
            extension_type = trestle.common.file_utils.get_contextual_file_type(model_dir)
            model_path = model_dir / f'{mt[0]}{FileContentType.to_file_extension(extension_type)}'
            _, _, model = ModelUtils.load_distributed(model_path, trestle_root)
            if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
                logger.info(f'INVALID: Model {model_path} did not pass the {self.error_msg()}')
                return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
            if not args.quiet:
                logger.info(f'VALID: Model {model_path} passed the {self.error_msg()}')
        return CmdReturnCodes.SUCCESS.value

    # validate file
    if args.file:
        file_path = trestle_root / args.file
        _, _, model = ModelUtils.load_distributed(file_path, trestle_root)
        if not self.model_is_valid(model, args.quiet, trestle_root):  # type: ignore
            logger.info(f'INVALID: Model {file_path} did not pass the {self.error_msg()}')
            return CmdReturnCodes.OSCAL_VALIDATION_ERROR.value
        if not args.quiet:
            logger.info(f'VALID: Model {file_path} passed the {self.error_msg()}')
    return CmdReturnCodes.SUCCESS.value

handler: python