Exemplo n.º 1
0
def test_ssp_writer(testdata_dir: pathlib.Path, tmp_trestle_dir: pathlib.Path,
                    monkeypatch: MonkeyPatch) -> None:
    """Test ssp writer from cli."""
    gen_args, _, _ = setup_for_ssp(True, True, tmp_trestle_dir, prof_name,
                                   ssp_name)

    profile_path, ssp_obj = setup_test(tmp_trestle_dir, testdata_dir,
                                       gen_args.trestle_root)

    resolved_catalog = profile_resolver.ProfileResolver.get_resolved_profile_catalog(
        tmp_trestle_dir, profile_path)
    ssp_writer = SSPMarkdownWriter(gen_args.trestle_root)
    ssp_writer.set_catalog(resolved_catalog)
    md_text = ssp_writer.get_control_statement('ac-2', 1)
    assert md_text is not None

    ssp_writer.set_ssp(ssp_obj)
    roles_md = ssp_writer.get_responsible_roles_table('ac-2', 1)
    assert roles_md

    md_text1 = ssp_writer._parameter_table('ac-2', 1)
    assert md_text1

    md_text3 = ssp_writer.get_fedramp_control_tables('ac-2', 1)
    assert md_text3

    md_text4 = ssp_writer.get_control_part('ac-2', 'item', 1)
    assert md_text4
Exemplo n.º 2
0
def test_ssp_generate(import_cat, specify_sections,
                      tmp_trestle_dir: pathlib.Path) -> None:
    """Test the ssp generator."""
    args, sections, yaml_path = setup_for_ssp(True, False, tmp_trestle_dir,
                                              prof_name, ssp_name, import_cat)
    if specify_sections:
        args.allowed_sections = 'ImplGuidance,ExpectedEvidence'

    ssp_cmd = SSPGenerate()
    # run the command for happy path
    assert ssp_cmd._run(args) == 0
    ac_dir = tmp_trestle_dir / (ssp_name + '/ac')
    ac_1 = ac_dir / 'ac-1.md'
    ac_2 = ac_dir / 'ac-2.md'
    assert ac_1.exists()
    assert ac_2.exists()
    assert ac_1.stat().st_size > 1000
    assert ac_2.stat().st_size > 2000

    with open(yaml_path, 'r', encoding=const.FILE_ENCODING) as f:
        yaml = YAML()
        expected_header = yaml.load(f)
    sections_dict = sections_to_dict(sections)
    expected_header[const.SECTIONS_TAG] = sections_dict
    assert test_utils.confirm_text_in_file(
        ac_1, '## Control', '## Control Guidance') != specify_sections
    md_api = MarkdownAPI()
    header, tree = md_api.processor.process_markdown(ac_1)
    assert tree is not None
    assert expected_header == header
    header, tree = md_api.processor.process_markdown(ac_2)
    assert tree is not None
    assert expected_header == header
Exemplo n.º 3
0
def test_ssp_generate_fail_statement_section(
        tmp_trestle_dir: pathlib.Path) -> None:
    """
    Test the ssp generator fails if 'statement' is provided.

    Also checking code where not label is provided.
    """
    args, _, _ = setup_for_ssp(False, False, tmp_trestle_dir, prof_name,
                               ssp_name)
    args.sections = 'statement'
    ssp_cmd = SSPGenerate()
    # run the command for happy path
    assert ssp_cmd._run(args) > 0
Exemplo n.º 4
0
def test_ssp_generate_resolved_catalog(tmp_trestle_dir: pathlib.Path) -> None:
    """Test the ssp generator to create a resolved profile catalog."""
    _, _, _ = setup_for_ssp(False, True, tmp_trestle_dir, prof_name, ssp_name)
    profile_path = tmp_trestle_dir / f'profiles/{prof_name}/profile.json'
    new_catalog_dir = tmp_trestle_dir / f'catalogs/{prof_name}_resolved_catalog'
    new_catalog_dir.mkdir(parents=True, exist_ok=True)
    new_catalog_path = new_catalog_dir / 'catalog.json'

    profile_resolver = ProfileResolver()
    resolved_catalog = profile_resolver.get_resolved_profile_catalog(
        tmp_trestle_dir, profile_path)
    assert resolved_catalog
    # FIXME this should test with a more complex catalog
    assert len(resolved_catalog.groups) == 1

    resolved_catalog.oscal_write(new_catalog_path)
Exemplo n.º 5
0
def test_ssp_generate_header_edit(yaml_header: bool,
                                  tmp_trestle_dir: pathlib.Path) -> None:
    """Test ssp generate does not overwrite header edits."""
    # always start by creating the markdown with the yaml header
    args, sections, yaml_path = setup_for_ssp(True, False, tmp_trestle_dir,
                                              prof_name, ssp_name)
    ssp_cmd = SSPGenerate()
    assert ssp_cmd._run(args) == 0

    ac_dir = tmp_trestle_dir / (ssp_name + '/ac')
    ac_1 = ac_dir / 'ac-1.md'

    with open(yaml_path, 'r', encoding=const.FILE_ENCODING) as f:
        yaml = YAML()
        yaml_header = yaml.load(f)

    md_api = MarkdownAPI()
    header, tree = md_api.processor.process_markdown(ac_1)
    assert tree is not None
    # remove the sections that were added to original header so we can check other changes in header
    header.pop(const.SECTIONS_TAG)
    assert yaml_header == header

    # edit the header by adding a list item and removing a value
    assert test_utils.insert_text_in_file(ac_1, 'System Specific',
                                          '  - My new edits\n')
    assert test_utils.delete_line_in_file(ac_1, 'Corporate')

    # if the yaml header is not written out, the new header should be the one currently in the control
    # if the yaml header is written out, it is merged with the current header giving priority to current header
    # so if not written out, the header should have one item added and another deleted due to edits in this test
    # if written out, it should just have the one added item because the deleted one will be put back in

    # tell it not to add the yaml header
    if not yaml_header:
        args.yaml_header = None

    assert ssp_cmd._run(args) == 0
    header, tree = md_api.processor.process_markdown(ac_1)
    assert tree is not None

    assert len(header['control-origination']) == 2
    if not yaml_header:
        assert 'new' in header['control-origination'][0]
    else:
        assert 'new' not in header['control-origination'][0]
Exemplo n.º 6
0
def test_ssp_get_control_response(tmp_trestle_dir: pathlib.Path,
                                  monkeypatch: MonkeyPatch) -> None:
    """Test generating SSP from the sample profile and generate markdown representation of it."""
    args, _, _ = setup_for_ssp(True, True, tmp_trestle_dir, prof_name,
                               ssp_name)
    ssp_cmd = SSPGenerate()
    assert ssp_cmd._run(args) == 0

    # set responses
    assert insert_prose(tmp_trestle_dir, 'ac-1_smt.b', 'This is a response')
    assert insert_prose(tmp_trestle_dir, 'ac-1_smt.c',
                        'This is also a response.')
    assert insert_prose(tmp_trestle_dir, 'ac-1_smt.a', 'This is a response.')

    command_ssp_gen = 'trestle author ssp-assemble -m my_ssp -o ssp_json'
    execute_command_and_assert(command_ssp_gen, 0, monkeypatch)

    ssp_json_path = tmp_trestle_dir / 'system-security-plans/ssp_json/system-security-plan.json'
    profile_path = tmp_trestle_dir / 'profiles/main_profile/profile.json'
    fetcher = cache.FetcherFactory.get_fetcher(tmp_trestle_dir,
                                               str(ssp_json_path))
    ssp_obj, _ = fetcher.get_oscal(True)

    resolved_catalog = profile_resolver.ProfileResolver.get_resolved_profile_catalog(
        tmp_trestle_dir, profile_path)

    ssp_io = SSPMarkdownWriter(tmp_trestle_dir)
    ssp_io.set_catalog(resolved_catalog)
    ssp_io.set_ssp(ssp_obj)

    md_text = ssp_io.get_control_response('ac-1', 1, True)
    assert md_text
    tree = MarkdownNode.build_tree_from_markdown(md_text.split('\n'))

    assert tree.get_node_for_key('## Part a.')
    assert tree.get_node_for_key('## Part c.')
    assert len(list(tree.get_all_headers_for_level(2))) == 3

    md_text = ssp_io.get_control_response('ac-1', 2, False)
    tree = MarkdownNode.build_tree_from_markdown(md_text.split('\n'))

    assert tree.get_node_for_key('### Part a.')
    assert tree.get_node_for_key('### Part c.')
    assert len(list(tree.get_all_headers_for_level(3))) == 3
Exemplo n.º 7
0
def test_ssp_generate_no_header(tmp_trestle_dir: pathlib.Path) -> None:
    """Test the ssp generator with no yaml header."""
    args, _, _ = setup_for_ssp(False, False, tmp_trestle_dir, prof_name,
                               ssp_name)
    ssp_cmd = SSPGenerate()
    args.sections = None
    # run the command for happy path
    assert ssp_cmd._run(args) == 0
    ac_dir = tmp_trestle_dir / (ssp_name + '/ac')
    ac_1 = ac_dir / 'ac-1.md'
    ac_2 = ac_dir / 'ac-2.md'
    assert ac_1.exists()
    assert ac_2.exists()
    assert ac_1.stat().st_size > 1000
    assert ac_2.stat().st_size > 2000

    md_api = MarkdownAPI()
    header, tree = md_api.processor.process_markdown(ac_1)
    assert tree is not None
    assert not header
    header, tree = md_api.processor.process_markdown(ac_2)
    assert tree is not None
    assert not header
Exemplo n.º 8
0
def test_ssp_filter(tmp_trestle_dir: pathlib.Path) -> None:
    """Test the ssp filter."""
    # install the catalog and profiles
    gen_args, _, _ = setup_for_ssp(False, False, tmp_trestle_dir, prof_name,
                                   ssp_name, True)
    # create markdown with profile a
    gen_args.profile = 'test_profile_a'
    ssp_gen = SSPGenerate()
    assert ssp_gen._run(gen_args) == 0

    # create ssp from the markdown
    ssp_assemble = SSPAssemble()
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              markdown=ssp_name,
                              output=ssp_name,
                              verbose=0,
                              name=None,
                              version=None,
                              regenerate=False)
    assert ssp_assemble._run(args) == 0

    # load the ssp so we can add a setparameter to it for more test coverage
    ssp, _ = ModelUtils.load_top_level_model(tmp_trestle_dir, ssp_name,
                                             ossp.SystemSecurityPlan,
                                             FileContentType.JSON)
    new_setparam = ossp.SetParameter(param_id='ac-1_prm_1',
                                     values=['new_value'])
    ssp.control_implementation.set_parameters = [new_setparam]
    ModelUtils.save_top_level_model(ssp, tmp_trestle_dir, ssp_name,
                                    FileContentType.JSON)

    filtered_name = 'filtered_ssp'

    # now filter the ssp through test_profile_d
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              name=ssp_name,
                              profile='test_profile_d',
                              output=filtered_name,
                              verbose=0,
                              regenerate=False,
                              version=None)
    ssp_filter = SSPFilter()
    assert ssp_filter._run(args) == 0

    orig_uuid = test_utils.get_model_uuid(tmp_trestle_dir, filtered_name,
                                          ossp.SystemSecurityPlan)

    # filter it again to confirm uuid is same
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              name=ssp_name,
                              profile='test_profile_d',
                              output=filtered_name,
                              verbose=0,
                              regenerate=False,
                              version=None)
    ssp_filter = SSPFilter()
    assert ssp_filter._run(args) == 0

    assert orig_uuid == test_utils.get_model_uuid(tmp_trestle_dir,
                                                  filtered_name,
                                                  ossp.SystemSecurityPlan)

    # filter again to confirm uuid is different with regen
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              name=ssp_name,
                              profile='test_profile_d',
                              output=filtered_name,
                              verbose=0,
                              regenerate=True,
                              version=None)
    ssp_filter = SSPFilter()
    assert ssp_filter._run(args) == 0

    assert orig_uuid != test_utils.get_model_uuid(
        tmp_trestle_dir, filtered_name, ossp.SystemSecurityPlan)

    # now filter the ssp through test_profile_b to force error because b references controls not in the ssp
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              name=ssp_name,
                              profile='test_profile_b',
                              output=filtered_name,
                              verbose=0,
                              regenerate=True,
                              version=None)
    ssp_filter = SSPFilter()
    assert ssp_filter._run(args) == 1
Exemplo n.º 9
0
def test_ssp_assemble(tmp_trestle_dir: pathlib.Path) -> None:
    """Test ssp assemble from cli."""
    gen_args, _, _ = setup_for_ssp(True, True, tmp_trestle_dir, prof_name,
                                   ssp_name)

    # first create the markdown
    ssp_gen = SSPGenerate()
    assert ssp_gen._run(gen_args) == 0
    acme_string = 'Do the ACME requirements'
    new_version = '1.2.3'

    prose_a = 'Hello there\n  How are you\n line with more text\n\ndouble line'
    prose_b = 'This is fun\nline with *bold* text\n\n### ACME Component\n\n' + acme_string

    # edit it a bit
    assert insert_prose(tmp_trestle_dir, 'ac-1_smt.a', prose_a)
    assert insert_prose(tmp_trestle_dir, 'ac-1_smt.b', prose_b)

    # generate markdown again on top of previous markdown to make sure it is not removed
    ssp_gen = SSPGenerate()
    assert ssp_gen._run(gen_args) == 0

    # now assemble the edited controls into json ssp
    ssp_assemble = SSPAssemble()
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              markdown=ssp_name,
                              output=ssp_name,
                              verbose=0,
                              regenerate=False,
                              version=new_version,
                              name=None)
    assert ssp_assemble._run(args) == 0

    orig_ssp, orig_ssp_path = ModelUtils.load_top_level_model(
        tmp_trestle_dir, ssp_name, ossp.SystemSecurityPlan)
    orig_uuid = orig_ssp.uuid
    assert len(orig_ssp.system_implementation.components) == 2
    assert orig_ssp.metadata.version.__root__ == new_version
    assert ModelUtils.model_age(orig_ssp) < test_utils.NEW_MODEL_AGE_SECONDS

    orig_file_creation = orig_ssp_path.stat().st_mtime

    # now write it back out and confirm text is still there
    assert ssp_gen._run(gen_args) == 0
    assert confirm_control_contains(tmp_trestle_dir, 'ac-1', 'a.',
                                    'Hello there')
    assert confirm_control_contains(tmp_trestle_dir, 'ac-1', 'a.',
                                    'line with more text')
    assert confirm_control_contains(tmp_trestle_dir, 'ac-1', 'b.',
                                    'This is fun')

    # now assemble it again but don't regen uuid's and don't change version
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              markdown=ssp_name,
                              output=ssp_name,
                              verbose=0,
                              regenerate=False,
                              name=None,
                              version=None)
    assert ssp_assemble._run(args) == 0

    # confirm the file was not written out since no change
    assert orig_ssp_path.stat().st_mtime == orig_file_creation

    repeat_ssp, _ = ModelUtils.load_top_level_model(tmp_trestle_dir, ssp_name,
                                                    ossp.SystemSecurityPlan)
    assert orig_ssp.control_implementation == repeat_ssp.control_implementation
    assert orig_ssp.system_implementation == repeat_ssp.system_implementation
    assert len(repeat_ssp.system_implementation.components) == 2
    assert repeat_ssp.metadata.version.__root__ == new_version

    found_it = False
    for imp_req in repeat_ssp.control_implementation.implemented_requirements:
        if imp_req.control_id == 'ac-1':
            statements = imp_req.statements
            assert len(statements) == 3
            for statement in statements:
                for by_component in statement.by_components:
                    if by_component.description == acme_string:
                        found_it = True
                        assert len(statement.by_components) == 2
                        break
        if found_it:
            break
    assert found_it

    # assemble it again but regen uuid's
    # this should not regen uuid's because the file is not written out if only difference is uuid's
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              markdown=ssp_name,
                              output=ssp_name,
                              verbose=0,
                              regenerate=True,
                              name=None,
                              version=None)
    assert ssp_assemble._run(args) == 0
    assert orig_uuid == test_utils.get_model_uuid(tmp_trestle_dir, ssp_name,
                                                  ossp.SystemSecurityPlan)
    # confirm the file was not written out since no change
    assert orig_ssp_path.stat().st_mtime == orig_file_creation

    # assemble it again but give new version and regen uuid's
    args = argparse.Namespace(trestle_root=tmp_trestle_dir,
                              markdown=ssp_name,
                              output=ssp_name,
                              verbose=0,
                              regenerate=True,
                              name=None,
                              version='new version to force write')
    assert ssp_assemble._run(args) == 0
    assert orig_uuid != test_utils.get_model_uuid(tmp_trestle_dir, ssp_name,
                                                  ossp.SystemSecurityPlan)
    # confirm the file was not written out since no change
    assert orig_ssp_path.stat().st_mtime > orig_file_creation