Esempio n. 1
0
def test_update_last_modified(
        sample_catalog_rich_controls: catalog.Catalog) -> None:
    """Test update timestamps."""
    hour_ago = datetime.now().astimezone() - timedelta(
        seconds=const.HOUR_SECONDS)
    ModelUtils.update_last_modified(sample_catalog_rich_controls, hour_ago)
    assert sample_catalog_rich_controls.metadata.last_modified.__root__ == hour_ago
    ModelUtils.update_last_modified(sample_catalog_rich_controls)
    assert ModelUtils.model_age(
        sample_catalog_rich_controls) < test_utils.NEW_MODEL_AGE_SECONDS
Esempio n. 2
0
def test_catalog_assemble_version(sample_catalog_rich_controls: cat.Catalog,
                                  tmp_trestle_dir: pathlib.Path) -> None:
    """Test catalog assemble version."""
    cat_name = 'my_cat'
    md_name = 'my_md'
    new_version = '1.2.3'
    assembled_cat_name = 'my_assembled_cat'
    catalog_dir = tmp_trestle_dir / f'catalogs/{cat_name}'
    catalog_dir.mkdir(parents=True, exist_ok=True)
    catalog_path = catalog_dir / 'catalog.json'
    sample_catalog_rich_controls.oscal_write(catalog_path)
    markdown_path = tmp_trestle_dir / md_name
    catalog_generate = CatalogGenerate()
    catalog_generate.generate_markdown(tmp_trestle_dir, catalog_path,
                                       markdown_path, {}, False)
    CatalogAssemble.assemble_catalog(tmp_trestle_dir, md_name,
                                     assembled_cat_name, cat_name, False,
                                     False, new_version)
    assembled_cat, assembled_cat_path = ModelUtils.load_top_level_model(
        tmp_trestle_dir, assembled_cat_name, cat.Catalog)
    assert assembled_cat.metadata.version.__root__ == new_version
    assert ModelUtils.model_age(
        assembled_cat) < test_utils.NEW_MODEL_AGE_SECONDS

    creation_time = assembled_cat_path.stat().st_mtime

    # assemble same way again and confirm no new write
    CatalogAssemble.assemble_catalog(tmp_trestle_dir, md_name,
                                     assembled_cat_name, assembled_cat_name,
                                     False, False, new_version)

    assert creation_time == assembled_cat_path.stat().st_mtime

    # change version and confirm write
    CatalogAssemble.assemble_catalog(tmp_trestle_dir, md_name,
                                     assembled_cat_name, assembled_cat_name,
                                     False, False, 'xx')

    assert creation_time < assembled_cat_path.stat().st_mtime
Esempio n. 3
0
def test_profile_generate_assemble(add_header: bool, guid_dict: Dict,
                                   use_cli: bool, dir_exists: bool,
                                   set_parameters: bool,
                                   tmp_trestle_dir: pathlib.Path,
                                   monkeypatch: MonkeyPatch) -> None:
    """Test the profile markdown generator."""
    ac1_path, assembled_prof_dir, profile_path, markdown_path = setup_profile_generate(
        tmp_trestle_dir)
    yaml_header_path = test_utils.YAML_TEST_DATA_PATH / 'good_simple.yaml'

    # convert resolved profile catalog to markdown then assemble it after adding an item to a control
    if use_cli:
        test_args = f'trestle author profile-generate -n {prof_name} -o {md_name} -rs NeededExtra'.split(
        )
        if add_header:
            test_args.extend(['-y', str(yaml_header_path)])
        test_args.extend(['-s', all_sections_str])
        monkeypatch.setattr(sys, 'argv', test_args)
        assert Trestle().run() == 0

        edit_files(ac1_path, set_parameters, guid_dict)

        test_args = f'trestle author profile-assemble -n {prof_name} -m {md_name} -o {assembled_prof_name}'.split(
        )
        if set_parameters:
            test_args.append('-sp')
        if dir_exists:
            assembled_prof_dir.mkdir()
        monkeypatch.setattr(sys, 'argv', test_args)
        assert Trestle().run() == 0
    else:
        profile_generate = ProfileGenerate()
        yaml_header = {}
        if add_header:
            yaml = YAML()
            yaml_header = yaml.load(yaml_header_path.open('r'))
        sections_dict = sections_to_dict(all_sections_str)
        profile_generate.generate_markdown(tmp_trestle_dir, profile_path,
                                           markdown_path, yaml_header, False,
                                           sections_dict, 'NeededExtra')

        edit_files(ac1_path, set_parameters, guid_dict)

        if dir_exists:
            assembled_prof_dir.mkdir()
        assert ProfileAssemble.assemble_profile(tmp_trestle_dir, prof_name,
                                                md_name, assembled_prof_name,
                                                set_parameters, False, None,
                                                None, None) == 0

    # check the assembled profile is as expected
    profile: prof.Profile
    profile, _ = ModelUtils.load_top_level_model(tmp_trestle_dir,
                                                 assembled_prof_name,
                                                 prof.Profile,
                                                 FileContentType.JSON)
    assert ModelUtils.model_age(profile) < test_utils.NEW_MODEL_AGE_SECONDS
    # get the set_params in the assembled profile
    set_params = profile.modify.set_parameters
    if set_parameters:
        assert set_params[0].param_id == 'ac-1_prm_1'
        assert set_params[0].values[0].__root__ == 'all personnel'
        assert set_params[1].param_id == 'ac-1_prm_2'
        assert set_params[1].values[0].__root__ == 'Organization-level'
        assert set_params[1].values[1].__root__ == 'System-level'
        assert set_params[2].param_id == 'ac-1_prm_3'
        assert set_params[2].values[0].__root__ == 'new value'
    else:
        assert len(set_params) == 15

    # now create the resolved profile catalog from the assembled json profile and confirm the addition is there

    catalog = ProfileResolver.get_resolved_profile_catalog(
        tmp_trestle_dir, assembled_prof_dir / 'profile.json')
    catalog_interface = CatalogInterface(catalog)
    # confirm presence of all expected strings in the control named parts
    for name, exp_str in guid_dict['name_exp']:
        prose = catalog_interface.get_control_part_prose('ac-1', name)
        assert prose.find(exp_str) >= 0
Esempio n. 4
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