ssp_inheritance_api
trestle.core.crm.ssp_inheritance_api
¤
API for updating inheritance information in SSPs.
logger
¤
Classes¤
SSPInheritanceAPI
¤
API for updating inheritance information in SSPs through inheritance markdown.
Source code in trestle/core/crm/ssp_inheritance_api.py
class SSPInheritanceAPI():
"""API for updating inheritance information in SSPs through inheritance markdown."""
def __init__(self, inheritance_md_path: pathlib.Path, trestle_root: pathlib.Path) -> None:
"""Initialize the SSP Inheritance API class."""
self._inheritance_markdown_path: pathlib.Path = inheritance_md_path
self._trestle_root: pathlib.Path = trestle_root
def write_inheritance_as_markdown(
self, leveraged_ssp_reference: str, catalog_api: Optional[CatalogAPI] = None
) -> None:
"""
Write inheritance information to markdown.
Args:
leveraged_ssp_reference: Location of the SSP to write inheritance information from.
catalog_api: Catalog API to filter inheritance information by catalog.
Notes:
If a catalog API is provided, the written controls in the markdown will be filtered by the catalog.
"""
leveraged_ssp: ossp.SystemSecurityPlan = self._fetch_leveraged_ssp(leveraged_ssp_reference)
if catalog_api is not None:
control_imp: ossp.ControlImplementation = leveraged_ssp.control_implementation
new_imp_requirements: List[ossp.ImplementedRequirement] = []
for imp_requirement in as_list(control_imp.implemented_requirements):
control = catalog_api._catalog_interface.get_control(imp_requirement.control_id)
if control is not None:
new_imp_requirements.append(imp_requirement)
control_imp.implemented_requirements = new_imp_requirements
leveraged_ssp.control_implementation = control_imp
export_writer: ExportWriter = ExportWriter(
self._inheritance_markdown_path, leveraged_ssp, leveraged_ssp_reference
)
export_writer.write_exports_as_markdown()
def update_ssp_inheritance(self, ssp: ossp.SystemSecurityPlan) -> None:
"""
Update inheritance information in SSP.
Args:
ssp: SSP to update with inheritance information.
"""
logger.debug('Reading inheritance information from markdown.')
reader = ExportReader(self._inheritance_markdown_path, ssp)
ssp = reader.read_exports_from_markdown()
leveraged_ssp_reference = reader.get_leveraged_ssp_href()
leveraged_ssp: ossp.SystemSecurityPlan = self._fetch_leveraged_ssp(leveraged_ssp_reference)
link: common.Link = common.Link(href=leveraged_ssp_reference)
leveraged_auths: List[ossp.LeveragedAuthorization] = []
leveraged_auth: ossp.LeveragedAuthorization = gens.generate_sample_model(ossp.LeveragedAuthorization)
leveraged_components: List[str] = reader.get_leveraged_components()
if not leveraged_components:
logger.warning(
'No leveraged components mapped to the SSP. '
'Please edit the inheritance markdown to include the leveraged authorization.'
)
else:
existing_leveraged_auth: ossp.LeveragedAuthorization = self._leveraged_auth_from_existing(
as_list(ssp.system_implementation.leveraged_authorizations), link
)
if existing_leveraged_auth is not None:
leveraged_auth = existing_leveraged_auth
else:
leveraged_auth.links = as_list(leveraged_auth.links)
leveraged_auth.links.append(link)
leveraged_auth.title = f'Leveraged Authorization for {leveraged_ssp.metadata.title}'
leveraged_auths.append(leveraged_auth)
# Overwrite the leveraged authorization in the SSP. The only leveraged authorization should be the one
# coming from inheritance view
ssp.system_implementation.leveraged_authorizations = none_if_empty(leveraged_auths)
self._reconcile_components(ssp, leveraged_ssp, leveraged_components, leveraged_auth)
def _fetch_leveraged_ssp(self, leveraged_ssp_reference: str) -> ossp.SystemSecurityPlan:
"""Fetch the leveraged SSP."""
leveraged_ssp: ossp.SystemSecurityPlan
fetcher = FetcherFactory.get_fetcher(self._trestle_root, leveraged_ssp_reference)
try:
leveraged_ssp, _ = fetcher.get_oscal()
except TrestleError as e:
raise TrestleError(f'Unable to fetch ssp from {leveraged_ssp_reference}: {e}')
return leveraged_ssp
def _reconcile_components(
self,
ssp: ossp.SystemSecurityPlan,
leveraged_ssp: ossp.SystemSecurityPlan,
leveraged_components: List[str],
leveraged_auth: ossp.LeveragedAuthorization
) -> None:
"""Reconcile components in the leveraging SSP with those in the leveraged SSP."""
mapped_components: Dict[str, ossp.SystemComponent] = {}
for component in as_list(leveraged_ssp.system_implementation.components):
if component.title in leveraged_components:
mapped_components[component.uuid] = component
new_components: List[ossp.SystemComponent] = []
for component in as_list(ssp.system_implementation.components):
props_dict: Dict[str, str] = {prop.name: prop.value for prop in as_list(component.props)}
# If this component is part of the original SSP components, add
# and continue
if const.LEV_AUTH_UUID not in props_dict:
new_components.append(component)
continue
# If the leveraged component already exists, update the title, description, type, and status
original_comp_uuid = props_dict[const.INHERITED_UUID]
if original_comp_uuid in mapped_components:
original_component = mapped_components.pop(original_comp_uuid)
self._update_leveraged_system_component(component, original_component, leveraged_auth.uuid)
new_components.append(component)
# Add any remaining components to the new components
for component in mapped_components.values():
new_component: ossp.SystemComponent = gens.generate_sample_model(ossp.SystemComponent)
self._update_leveraged_system_component(new_component, component, leveraged_auth.uuid)
logger.debug(f'Adding component {new_component.title} to components.')
new_components.append(new_component)
ssp.system_implementation.components = new_components
@staticmethod
def _update_leveraged_system_component(
new_comp: ossp.SystemComponent, original_comp: ossp.SystemComponent, leveraged_auth_id: str
) -> None:
"""Create a leveraged system component in the context of a leveraging system component."""
new_comp.type = original_comp.type
new_comp.title = original_comp.title
new_comp.description = original_comp.description
new_comp.status = original_comp.status
new_comp.props = [
common.Property(name=const.IMPLEMENTATION_POINT, value=const.IMPLEMENTATION_POINT_EXTERNAL),
common.Property(name=const.LEV_AUTH_UUID, value=leveraged_auth_id),
common.Property(name=const.INHERITED_UUID, value=original_comp.uuid)
]
def _leveraged_auth_from_existing(
self, leveraged_authorizations: List[ossp.LeveragedAuthorization], criteria_link: common.Link
) -> Optional[ossp.LeveragedAuthorization]:
"""Return the leveraged authorization if it is present in the ssp."""
for leveraged_auth in leveraged_authorizations:
if leveraged_auth.links and any(link.href == criteria_link.href for link in leveraged_auth.links):
return leveraged_auth
return None
Methods¤
__init__(self, inheritance_md_path, trestle_root)
special
¤
Initialize the SSP Inheritance API class.
Source code in trestle/core/crm/ssp_inheritance_api.py
def __init__(self, inheritance_md_path: pathlib.Path, trestle_root: pathlib.Path) -> None:
"""Initialize the SSP Inheritance API class."""
self._inheritance_markdown_path: pathlib.Path = inheritance_md_path
self._trestle_root: pathlib.Path = trestle_root
update_ssp_inheritance(self, ssp)
¤
Update inheritance information in SSP.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
ssp |
SystemSecurityPlan |
SSP to update with inheritance information. |
required |
Source code in trestle/core/crm/ssp_inheritance_api.py
def update_ssp_inheritance(self, ssp: ossp.SystemSecurityPlan) -> None:
"""
Update inheritance information in SSP.
Args:
ssp: SSP to update with inheritance information.
"""
logger.debug('Reading inheritance information from markdown.')
reader = ExportReader(self._inheritance_markdown_path, ssp)
ssp = reader.read_exports_from_markdown()
leveraged_ssp_reference = reader.get_leveraged_ssp_href()
leveraged_ssp: ossp.SystemSecurityPlan = self._fetch_leveraged_ssp(leveraged_ssp_reference)
link: common.Link = common.Link(href=leveraged_ssp_reference)
leveraged_auths: List[ossp.LeveragedAuthorization] = []
leveraged_auth: ossp.LeveragedAuthorization = gens.generate_sample_model(ossp.LeveragedAuthorization)
leveraged_components: List[str] = reader.get_leveraged_components()
if not leveraged_components:
logger.warning(
'No leveraged components mapped to the SSP. '
'Please edit the inheritance markdown to include the leveraged authorization.'
)
else:
existing_leveraged_auth: ossp.LeveragedAuthorization = self._leveraged_auth_from_existing(
as_list(ssp.system_implementation.leveraged_authorizations), link
)
if existing_leveraged_auth is not None:
leveraged_auth = existing_leveraged_auth
else:
leveraged_auth.links = as_list(leveraged_auth.links)
leveraged_auth.links.append(link)
leveraged_auth.title = f'Leveraged Authorization for {leveraged_ssp.metadata.title}'
leveraged_auths.append(leveraged_auth)
# Overwrite the leveraged authorization in the SSP. The only leveraged authorization should be the one
# coming from inheritance view
ssp.system_implementation.leveraged_authorizations = none_if_empty(leveraged_auths)
self._reconcile_components(ssp, leveraged_ssp, leveraged_components, leveraged_auth)
write_inheritance_as_markdown(self, leveraged_ssp_reference, catalog_api=None)
¤
Write inheritance information to markdown.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
leveraged_ssp_reference |
str |
Location of the SSP to write inheritance information from. |
required |
catalog_api |
Optional[trestle.core.catalog.catalog_api.CatalogAPI] |
Catalog API to filter inheritance information by catalog. |
None |
Notes
If a catalog API is provided, the written controls in the markdown will be filtered by the catalog.
Source code in trestle/core/crm/ssp_inheritance_api.py
def write_inheritance_as_markdown(
self, leveraged_ssp_reference: str, catalog_api: Optional[CatalogAPI] = None
) -> None:
"""
Write inheritance information to markdown.
Args:
leveraged_ssp_reference: Location of the SSP to write inheritance information from.
catalog_api: Catalog API to filter inheritance information by catalog.
Notes:
If a catalog API is provided, the written controls in the markdown will be filtered by the catalog.
"""
leveraged_ssp: ossp.SystemSecurityPlan = self._fetch_leveraged_ssp(leveraged_ssp_reference)
if catalog_api is not None:
control_imp: ossp.ControlImplementation = leveraged_ssp.control_implementation
new_imp_requirements: List[ossp.ImplementedRequirement] = []
for imp_requirement in as_list(control_imp.implemented_requirements):
control = catalog_api._catalog_interface.get_control(imp_requirement.control_id)
if control is not None:
new_imp_requirements.append(imp_requirement)
control_imp.implemented_requirements = new_imp_requirements
leveraged_ssp.control_implementation = control_imp
export_writer: ExportWriter = ExportWriter(
self._inheritance_markdown_path, leveraged_ssp, leveraged_ssp_reference
)
export_writer.write_exports_as_markdown()
handler: python