Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: merge control markdown with json (#1528) #1740

Merged
merged 7 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions tests/trestle/core/control_io_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from trestle.common.model_utils import ModelUtils
from trestle.core.catalog.catalog_interface import CatalogInterface
from trestle.core.control_context import ContextPurpose, ControlContext
from trestle.core.control_interface import ControlInterface, ParameterRep
from trestle.core.control_interface import ComponentImpInfo, ControlInterface, ParameterRep
from trestle.core.control_reader import ControlReader
from trestle.core.control_writer import ControlWriter
from trestle.core.markdown.control_markdown_node import ControlMarkdownNode, tree_context
Expand All @@ -45,7 +45,7 @@
case_3 = 'indent end abrupt'
case_4 = 'no items'

control_text = """---
control_text = r"""---
x-trestle-global:
sort-id: xy-09
---
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_read_write_controls(
part_b3 = common.Part(id='ac-1_smt.b.3', name='item', prose='b.3 prose', props=[prop])
prop.value = 'c'
part_c = common.Part(id='ac-1_smt.c', name='item', prose='c prose', props=[prop])
sec_1_text = """
sec_1_text = r"""
General comment
on separate lines

Expand Down Expand Up @@ -395,7 +395,47 @@ def test_write_control_header_params(overwrite_header_values, tmp_path: pathlib.
assert test_utils.controls_equivalent(orig_control_read, new_control_read)


statement_text = """
def test_merge_control_update(tmp_path: pathlib.Path, testdata_dir: pathlib.Path) -> None:
"""Test merging of control header params after spec update."""
src_control_path = pathlib.Path(testdata_dir / 'author/controls/control_with_components.md')
control_path = tmp_path / 'ac-1.md'
shutil.copyfile(src_control_path, control_path)
orig_control_read, group_title = ControlReader.read_control(control_path, False)
assert group_title == 'Access Control'
context = ControlContext.generate(ContextPurpose.COMPONENT, True, tmp_path, tmp_path, True)
# Given updated template comp_dict from the component definition json
context.comp_dict = {
'This System': {
'': ComponentImpInfo(
prose='', rules=[], props=[], status=common.ImplementationStatus(state='planned', remarks=None)
),
'a.': ComponentImpInfo(
prose='Text for fancy thing component',
rules=[],
props=[],
status=common.ImplementationStatus(state='planned', remarks=None)
),
'c.': ComponentImpInfo(
prose='Just for the default component',
rules=[],
props=[],
status=common.ImplementationStatus(state='planned', remarks=None)
),
'd.': ComponentImpInfo(
prose='Example extra component',
rules=[],
props=[],
status=common.ImplementationStatus(state='planned', remarks=None)
)
}
}
control_writer = ControlWriter()
control_writer.write_control_for_editing(context, orig_control_read, tmp_path, group_title, {}, [])
assert context.comp_dict['This System']['c.'].status.state == 'operational', 'State must be merged'
assert context.comp_dict['This System']['d.'].status.state == 'planned', 'New template state must be merged'


statement_text = r"""


# xy-9 - \[My Group Title\] Fancy Control
Expand Down
2 changes: 1 addition & 1 deletion trestle/core/catalog/catalog_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -904,5 +904,5 @@ def generate_control_rule_info(self, part_id_map: Dict[str, Dict[str, str]], con
if len(dup_comp_uuids) > 0:
# throw an exception if there are repeated component uuids
for comp_uuid in dup_comp_uuids:
logger.error(f'Component uuid { comp_uuid } is duplicated')
logger.error(f'Component uuid {comp_uuid} is duplicated')
raise TrestleError('Component uuids cannot be duplicated between different component definitions')
6 changes: 4 additions & 2 deletions trestle/core/control_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ class ControlInterface:

@staticmethod
def _wrap_label(label: str):
l_side = '\['
r_side = '\]'
l_side = r'\['
r_side = r'\]'
wrapped = '' if label == '' else f'{l_side}{label}{r_side}'
return wrapped

Expand Down Expand Up @@ -591,6 +591,8 @@ def merge_dicts_deep(
New items are always added from src to dest.
Items present in both will be overriden dest if overwrite_header_values is True.
"""
if src is None:
return
for key in src.keys():
if key in dest:
if depth and level == depth:
Expand Down
6 changes: 4 additions & 2 deletions trestle/core/control_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _add_control_statement(self, control: cat.Control, group_title: str, print_g
control_title = control.title

if print_group_title:
group_name = ' \[' + group_title + '\]'
group_name = r' \[' + group_title + r'\]'

title = f'{control_id} -{group_name} {control_title}'

Expand Down Expand Up @@ -516,8 +516,10 @@ def write_control_for_editing(
control_file = dest_path / (control.id + const.MARKDOWN_FILE_EXT)
# read the existing markdown header and content if it exists
md_header, comp_dict = ControlReader.read_control_info_from_md(control_file, context)
# replace the memory comp_dict with the md one if control exists
# Merge the memory comp_dict with the md one if control exists
if comp_dict:
template_comp_dict = context.comp_dict
ControlInterface.merge_dicts_deep(comp_dict, template_comp_dict, False)
context.comp_dict = comp_dict

header_comment_dict = {const.TRESTLE_ADD_PROPS_TAG: const.YAML_PROPS_COMMENT}
Expand Down
4 changes: 2 additions & 2 deletions trestle/transforms/implementations/tanium.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def transform(self, blob: str) -> Results:
results.__root__ = tanium_oscal_factory.results
ts1 = datetime.datetime.now()
self._analysis = tanium_oscal_factory.analysis
self._analysis.append(f'transform time: {ts1-ts0}')
self._analysis.append(f'transform time: {ts1 - ts0}')
return results


Expand Down Expand Up @@ -455,7 +455,7 @@ def _batch_observations(self, index: int) -> Dict[str, List[Observation]]:
start = index * batch_size
end = (index + 1) * batch_size
end = min(end, len(self._rule_use_list))
logger.debug(f'start: {start} end: {end-1}')
logger.debug(f'start: {start} end: {end - 1}')
# process just the one chunk
for i in range(start, end):
rule_use = self._rule_use_list[i]
Expand Down
Loading