コード例 #1
0
ファイル: remove_test.py プロジェクト: IBM/compliance-trestle
def test_run(tmp_path: pathlib.Path, sample_catalog_missing_roles,
             monkeypatch: MonkeyPatch):
    """Test _run for RemoveCmd."""
    # 1. Test trestle remove for one element.
    # expected catalog after remove of Responsible-Party
    file_path = pathlib.Path.joinpath(
        test_utils.JSON_TEST_DATA_PATH,
        'minimal_catalog_no_responsible-parties.json')
    expected_catalog_no_rp = Catalog.oscal_read(file_path)

    content_type = FileContentType.JSON

    # Create a temporary file with responsible-parties to be removed.
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_missing_roles,
        test_utils.CATALOGS_DIR)

    testargs = [
        'trestle', 'remove', '-tr',
        str(tmp_path), '-f',
        str(catalog_def_file), '-e', 'catalog.metadata.responsible-parties'
    ]

    monkeypatch.setattr(sys, 'argv', testargs)
    assert Trestle().run() == 0

    actual_catalog = Catalog.oscal_read(catalog_def_file)
    assert expected_catalog_no_rp == actual_catalog

    # 2. Test trestle remove for multiple comma-separated elements.
    # minimal catalog with Roles and Resposibile-Parties.
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles.json')
    catalog_with_roles_responsible_parties = Catalog.oscal_read(file_path)

    # Create a temporary file with Roles and Responsible-Parties to be removed.
    catalog_def_dir, catalog_def_file_2 = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, catalog_with_roles_responsible_parties,
        test_utils.CATALOGS_DIR)

    testargs = [
        'trestle', 'remove', '-tr',
        str(tmp_path), '-f',
        str(catalog_def_file_2), '-e',
        'catalog.metadata.responsible-parties,catalog.metadata.roles'
    ]

    monkeypatch.setattr(sys, 'argv', testargs)
    assert Trestle().run() == 0

    actual_catalog = Catalog.oscal_read(catalog_def_file_2)
    assert expected_catalog_no_rp == actual_catalog
コード例 #2
0
def test_href_cmd(tmp_path: pathlib.Path, keep_cwd: pathlib.Path,
                  simplified_nist_profile: profile.Profile,
                  monkeypatch: MonkeyPatch) -> None:
    """Test basic cmd invocation of href."""
    # prepare trestle project dir with the file
    models_path, profile_path = test_utils.prepare_trestle_project_dir(
        tmp_path, FileContentType.JSON, simplified_nist_profile,
        test_utils.PROFILES_DIR)

    os.chdir(models_path)

    # just list the hrefs
    cmd_string = 'trestle href -n my_test_model'
    monkeypatch.setattr(sys, 'argv', cmd_string.split())
    rc = Trestle().run()
    assert rc == 0

    orig_href = simplified_nist_profile.imports[0].href

    new_href = 'trestle://catalogs/my_catalog/catalog.json'

    cmd_string = f'trestle href -n my_test_model -hr {new_href}'
    monkeypatch.setattr(sys, 'argv', cmd_string.split())
    rc = Trestle().run()
    assert rc == 0

    # confirm new href is correct
    new_profile: profile.Profile = profile.Profile.oscal_read(profile_path)
    assert new_profile.imports[0].href == new_href

    # restore orig href to confirm models are otherwise equivalent
    # only thing different should be last-modified
    new_profile.imports[0].href = orig_href
    assert test_utils.models_are_equivalent(new_profile,
                                            simplified_nist_profile)
コード例 #3
0
def test_split_model_at_path_chain_failures(
        tmp_path, simplified_nist_catalog: oscatalog.Catalog) -> None:
    """Test for split_model_at_path_chain method failure scenarios."""
    content_type = FileContentType.JSON

    # prepare trestle project dir with the file
    catalog_dir, catalog_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, simplified_nist_catalog,
        test_utils.CATALOGS_DIR)

    split_plan = Plan()
    element_paths = [ElementPath('catalog.metadata.parties.*')]

    # no plan should error
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(simplified_nist_catalog,
                                           element_paths, catalog_dir,
                                           content_type, 0, None, False, '',
                                           None)

    # negative path index should error
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(simplified_nist_catalog,
                                           element_paths, catalog_dir,
                                           content_type, -1, split_plan, False,
                                           '', None)

    # too large path index should return the path index
    cur_path_index = len(element_paths) + 1
    SplitCmd.split_model_at_path_chain(simplified_nist_catalog, element_paths,
                                       catalog_dir, content_type,
                                       cur_path_index, split_plan, False, '',
                                       None)
コード例 #4
0
ファイル: remove_test.py プロジェクト: IBM/compliance-trestle
def test_run_failure_plan_execute(tmp_path: pathlib.Path,
                                  sample_catalog_minimal: Catalog,
                                  monkeypatch: MonkeyPatch,
                                  caplog: pytest.LogCaptureFixture):
    """Test failure plan execute() in _run on RemoveCmd."""
    # Plant this specific logged error for failing execution in mock_execute:
    logged_error = 'fail_execute'

    def mock_execute(*args, **kwargs):
        raise err.TrestleError(logged_error)

    # Create a temporary file as a valid arg for trestle remove:
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    monkeypatch.chdir(tmp_path)
    # Add remarks here, so it is a valid removal target,
    testargs = [
        'trestle', 'create', '-f',
        str(catalog_def_file), '-e', 'catalog.metadata.remarks'
    ]
    monkeypatch.setattr(sys, 'argv', testargs)
    Trestle().run()
    # .. then attempt to remove it here, but mocking a failed execute:
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.metadata.remarks'
    ]
    monkeypatch.setattr(Plan, 'execute', mock_execute)
    monkeypatch.setattr(sys, 'argv', testargs)
    caplog.clear()
    rc = Trestle().run()
    assert rc > 0
コード例 #5
0
def test_href_failures(tmp_path: pathlib.Path, keep_cwd: pathlib.Path,
                       simplified_nist_profile: profile.Profile,
                       monkeypatch: MonkeyPatch) -> None:
    """Test href failure modes."""
    # prepare trestle project dir with the file
    models_path, profile_path = test_utils.prepare_trestle_project_dir(
        tmp_path, FileContentType.JSON, simplified_nist_profile,
        test_utils.PROFILES_DIR)

    cmd_string = 'trestle href -n my_test_model -hr foobar'

    # not in trestle project so fail
    monkeypatch.setattr(sys, 'argv', cmd_string.split())
    rc = Trestle().run()
    assert rc == 5

    os.chdir(models_path)

    cmd_string = 'trestle href -n my_test_model -hr foobar -i 2'

    # add extra import to the profile and ask for import number 2
    simplified_nist_profile.imports.append(simplified_nist_profile.imports[0])
    simplified_nist_profile.oscal_write(profile_path)
    monkeypatch.setattr(sys, 'argv', cmd_string.split())
    rc = Trestle().run()
    assert rc == 1
コード例 #6
0
ファイル: remove_test.py プロジェクト: IBM/compliance-trestle
def test_run_failure_nonexistent_element(tmp_path: pathlib.Path,
                                         sample_catalog_minimal: Catalog,
                                         monkeypatch: MonkeyPatch):
    """Test failure of _run on RemoveCmd in specifying nonexistent element for removal."""
    # Create a temporary catalog file with responsible-parties
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)

    # 1. self.remove() fails -- Should happen if wildcard is given, or nonexistent element.
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.blah'
    ]
    monkeypatch.setattr(sys, 'argv', testargs)
    exitcode = Trestle().run()
    assert exitcode == 5

    # 2. Corrupt json file
    source_file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                             'bad_simple.json')
    shutil.copyfile(source_file_path, catalog_def_file)
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.metadata.roles'
    ]
    monkeypatch.setattr(sys, 'argv', testargs)
    exitcode = Trestle().run()
    assert exitcode == 5
コード例 #7
0
def test_add(tmp_path: pathlib.Path, keep_cwd: pathlib.Path) -> None:
    """Test Add.add() method used by trestle CreateCmd."""
    file_path = pathlib.Path(
        test_utils.JSON_TEST_DATA_PATH) / 'minimal_catalog_missing_roles.json'
    minimal_catalog_missing_roles = Catalog.oscal_read(file_path)

    # expected catalog after first add of Role
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles.json')
    expected_catalog_roles1 = Element(Catalog.oscal_read(file_path))

    # expected catalog after second add of Role
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles_double.json')
    expected_catalog_roles2 = Element(Catalog.oscal_read(file_path))

    # expected catalog after add of Responsible-Party
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles_double_rp.json')
    expected_catalog_roles2_rp = Element(Catalog.oscal_read(file_path))

    content_type = FileContentType.JSON

    _, _ = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, minimal_catalog_missing_roles,
        test_utils.CATALOGS_DIR)

    # Execute first _add
    element_path = ElementPath('catalog.metadata.roles')
    catalog_element = Element(minimal_catalog_missing_roles)
    expected_update_action_1 = UpdateAction(
        expected_catalog_roles1.get_at(element_path), catalog_element,
        element_path)
    actual_update_action, actual_catalog_roles = Add.add(
        element_path, catalog_element, False)

    assert actual_catalog_roles == expected_catalog_roles1
    assert actual_update_action == expected_update_action_1

    # Execute second _add - this time roles already exists, so this adds a roles object to roles array
    catalog_element = actual_catalog_roles
    expected_update_action_2 = UpdateAction(
        expected_catalog_roles2.get_at(element_path), catalog_element,
        element_path)
    actual_update_action2, actual_catalog_roles2 = Add.add(
        element_path, catalog_element, False)
    assert actual_catalog_roles2 == expected_catalog_roles2
    assert actual_update_action2 == expected_update_action_2

    # Execute _add for responsible-parties to the same catalog
    element_path = ElementPath('catalog.metadata.responsible-parties')
    catalog_element = actual_catalog_roles2
    expected_update_action_3 = UpdateAction(
        expected_catalog_roles2_rp.get_at(element_path), catalog_element,
        element_path)
    actual_update_action3, actual_catalog_roles2_rp = Add.add(
        element_path, catalog_element, False)
    assert actual_catalog_roles2_rp == expected_catalog_roles2_rp
    assert actual_update_action3 == expected_update_action_3
コード例 #8
0
def test_split_chained_sub_model_plans(
        tmp_path: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog,
        keep_cwd: pathlib.Path) -> None:
    """Test for split_model method with chained sum models like catalog.metadata.parties.*."""
    # Assume we are running a command like below
    # trestle split -f catalog.json -e catalog.metadata.parties.*
    # see https://github.com/IBM/compliance-trestle/issues/172
    content_type = FileContentType.JSON

    # prepare trestle project dir with the file
    catalog_dir, catalog_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, simplified_nist_catalog,
        test_utils.CATALOGS_DIR)

    # read the model from file
    catalog = oscatalog.Catalog.oscal_read(catalog_file)
    element = Element(catalog)
    element_args = ['catalog.metadata.parties.*']
    element_paths = cmd_utils.parse_element_args(
        None, element_args, catalog_dir.relative_to(tmp_path))
    assert 2 == len(element_paths)

    expected_plan = Plan()

    # prepare to extract metadata and parties
    metadata_file = catalog_dir / element_paths[0].to_file_path(content_type)
    metadata_field_alias = element_paths[0].get_element_name()
    metadata = element.get_at(element_paths[0])
    meta_element = Element(metadata, metadata_field_alias)

    # extract parties
    parties_dir = catalog_dir / 'catalog/metadata/parties'
    for i, party in enumerate(meta_element.get_at(element_paths[1], False)):
        prefix = str(i).zfill(const.FILE_DIGIT_PREFIX_LENGTH)
        sub_model_actions = SplitCmd.prepare_sub_model_split_actions(
            party, parties_dir, prefix, content_type)
        expected_plan.add_actions(sub_model_actions)

    # stripped metadata
    stripped_metadata = metadata.stripped_instance(
        stripped_fields_aliases=['parties'])
    expected_plan.add_action(CreatePathAction(metadata_file))
    expected_plan.add_action(
        WriteFileAction(metadata_file,
                        Element(stripped_metadata, metadata_field_alias),
                        content_type))

    # stripped catalog
    root_file = catalog_dir / element_paths[0].to_root_path(content_type)
    remaining_root = element.get().stripped_instance(metadata_field_alias)
    expected_plan.add_action(CreatePathAction(root_file, True))
    expected_plan.add_action(
        WriteFileAction(root_file, Element(remaining_root), content_type))

    split_plan = SplitCmd.split_model(catalog, element_paths, catalog_dir,
                                      content_type, '', None)
    assert expected_plan == split_plan
コード例 #9
0
def test_split_model_at_path_chain_failures(tmp_path,
                                            sample_catalog: oscatalog.Catalog):
    """Test for split_model_at_path_chain method failure scenarios."""
    content_type = FileContentType.JSON

    # prepare trestle project dir with the file
    catalog_dir, catalog_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog, test_utils.CATALOGS_DIR)

    split_plan = Plan()
    element_paths = [ElementPath('catalog.metadata.parties.*')]

    # long chain of path should error
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                           catalog_dir, content_type, 0,
                                           split_plan, False)

    # no plan should error
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                           catalog_dir, content_type, 0, None,
                                           False)

    # negative path index should error
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                           catalog_dir, content_type, -1,
                                           split_plan, False)

    # too large path index should return the path index
    cur_path_index = len(element_paths) + 1
    SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                       catalog_dir, content_type,
                                       cur_path_index, split_plan, False)

    # invalid model path should return withour doing anything
    element_paths = [ElementPath('catalog.meta')]
    cur_path_index = 0
    SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                       catalog_dir, content_type,
                                       cur_path_index, split_plan, False)

    # invalid path for multi item sub-model
    p0 = ElementPath(
        'catalog.uuid.*'
    )  # uuid exists, but it is not a multi-item sub-model object
    p1 = ElementPath(
        'uuid.metadata.*', p0
    )  # this is invalid but we just need a path with the p0 as the parent
    element_paths = [p0, p1]
    with pytest.raises(TrestleError):
        SplitCmd.split_model_at_path_chain(sample_catalog, element_paths,
                                           catalog_dir, content_type, 0,
                                           split_plan, False)
コード例 #10
0
def test_run_failure_wildcard(tmp_path, sample_catalog_minimal):
    """Test failure of _run on RemoveCmd in specifying wildcard in element for removal."""
    # Create a temporary catalog file with responsible-parties
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.*'
    ]
    with patch.object(sys, 'argv', testargs):
        exitcode = Trestle().run()
        assert exitcode == 1
コード例 #11
0
def test_run_failure_project_not_found(tmp_path, sample_catalog_minimal):
    """Test failure of _run on RemoveCmd in specifying file in non-initialized location."""
    # Create a temporary catalog file with responsible-parties
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    # 5. get_contextual_model_type() fails, i.e., "Trestle project not found"
    testargs = [
        'trestle', 'remove', '-f', '/dev/null', '-e', 'catalog.metadata'
    ]
    with patch.object(sys, 'argv', testargs):
        exitcode = Trestle().run()
        assert exitcode == 1
コード例 #12
0
def test_run_failure_required_element(tmp_path, sample_catalog_minimal):
    """Test failure of _run on RemoveCmd in specifying a required element for removal."""
    # Create a temporary catalog file with responsible-parties
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    # 4. simulate() fails -- Should happen if required element is target for deletion
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.metadata'
    ]
    with patch.object(sys, 'argv', testargs):
        exitcode = Trestle().run()
        assert exitcode == 1
コード例 #13
0
def test_add(tmp_dir, sample_catalog_minimal):
    """Test AddCmd.add() method for trestle add."""
    # expected catalog after first add of Role
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles.json')
    expected_catalog_roles1 = Catalog.oscal_read(file_path)

    # expected catalog after second add of Role
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles_double.json')
    expected_catalog_roles2 = Catalog.oscal_read(file_path)

    # expected catalog after add of Responsible-Party
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles_double_rp.json')
    expected_catalog_roles2_rp = Catalog.oscal_read(file_path)

    content_type = FileContentType.JSON

    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_dir, content_type, sample_catalog_minimal, test_utils.CATALOGS_DIR)

    # Execute first _add
    element_path = ElementPath('catalog.metadata.roles')
    catalog_element = Element(sample_catalog_minimal)
    AddCmd.add(catalog_def_dir / catalog_def_file, element_path, Catalog,
               catalog_element)

    actual_catalog_roles = Catalog.oscal_read(catalog_def_dir /
                                              catalog_def_file)
    assert actual_catalog_roles == expected_catalog_roles1

    # Execute second _add - this time roles already exists, so this adds a roles object to roles array
    catalog_element = Element(actual_catalog_roles)
    AddCmd.add(catalog_def_dir / catalog_def_file, element_path, Catalog,
               catalog_element)
    actual_catalog_roles2 = Catalog.oscal_read(catalog_def_dir /
                                               catalog_def_file)
    assert actual_catalog_roles2 == expected_catalog_roles2

    # Execute _add for responsible-parties to the same catalog
    element_path = ElementPath('catalog.metadata.responsible-parties')
    catalog_element = Element(actual_catalog_roles2)
    AddCmd.add(catalog_def_dir / catalog_def_file, element_path, Catalog,
               catalog_element)
    actual_catalog_roles2_rp = Catalog.oscal_read(catalog_def_dir /
                                                  catalog_def_file)
    assert actual_catalog_roles2_rp == expected_catalog_roles2_rp
コード例 #14
0
def test_run_failure_filenotfounderror(tmp_path, sample_catalog_minimal):
    """Test failure of _run on RemoveCmd in specifying a nonexistent file."""
    # Create a temporary catalog file with responsible-parties
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    # 6. oscal_read fails because file is not found
    # Must specify catalogs/ location, not catalogs/my_test_model/.
    testargs = [
        'trestle', 'remove', '-f',
        re.sub('my_test_model/', '', str(catalog_def_file)), '-e',
        'catalog.metadata'
    ]
    with patch.object(sys, 'argv', testargs):
        exitcode = Trestle().run()
        assert exitcode == 1
コード例 #15
0
def test_run_failure_plan_execute(tmp_path, sample_catalog_minimal):
    """Test failure plan execute() in _run on RemoveCmd."""
    # Create a temporary file as a valid arg for trestle remove:
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    testargs = [
        'trestle', 'remove', '-f',
        str(catalog_def_file), '-e', 'catalog.metadata.responsible-parties'
    ]

    with mock.patch('trestle.core.models.plans.Plan.simulate'):
        with mock.patch(
                'trestle.core.models.plans.Plan.execute') as execute_mock:
            execute_mock.side_effect = err.TrestleError('stuff')
            with patch.object(sys, 'argv', testargs):
                exitcode = Trestle().run()
                assert exitcode == 1
コード例 #16
0
def test_stripped_model(tmp_path: pathlib.Path, keep_cwd: pathlib.Path,
                        sample_catalog_minimal: Catalog,
                        monkeypatch: MonkeyPatch) -> None:
    """Test CreateCmd creating element for stripped model."""
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    os.chdir(catalog_def_dir)
    testargs = [
        'trestle', 'split', '-f', 'catalog.json', '-e', 'catalog.metadata'
    ]
    monkeypatch.setattr(sys, 'argv', testargs)
    assert Trestle().run() == 0

    # Now that the metadata has been split, add of catalog.metadata.roles will error,
    # but add of catalog.back-matter will pass

    testargs = [
        'trestle', 'create', '-f', 'catalog.json', '-e',
        'catalog.metadata.roles'
    ]

    monkeypatch.setattr(sys, 'argv', testargs)
    assert Trestle().run() == 1

    testargs = [
        'trestle', 'create', '-f', 'catalog.json', '-e', 'catalog.back-matter'
    ]

    current_model, _ = ModelUtils.get_stripped_model_type(
        catalog_def_dir, tmp_path)
    current_catalog = current_model.oscal_read(pathlib.Path('catalog.json'))
    current_catalog.back_matter = BackMatter()
    expected_catalog = current_catalog

    monkeypatch.setattr(sys, 'argv', testargs)
    assert Trestle().run() == 0

    actual_model, _ = ModelUtils.get_stripped_model_type(
        catalog_def_dir, tmp_path)
    actual_catalog = actual_model.oscal_read(pathlib.Path('catalog.json'))
    assert expected_catalog == actual_catalog
コード例 #17
0
def test_describe_functionality(
    element_path: str, tmp_path: pathlib.Path, keep_cwd: pathlib.Path, simplified_nist_catalog: oscatalog.Catalog
) -> None:
    """Test basic functionality of describe."""
    # prepare trestle project dir with the file
    catalog_dir, catalog_file = test_utils.prepare_trestle_project_dir(
        tmp_path,
        FileContentType.JSON,
        simplified_nist_catalog,
        test_utils.CATALOGS_DIR)

    os.chdir(catalog_dir)
    args = argparse.Namespace(file='catalog.json', element=element_path, verbose=1, trestle_root=tmp_path)
    assert DescribeCmd()._run(args) == 0

    results = DescribeCmd.describe(catalog_file.resolve(), '', tmp_path)
    assert len(results) > 5
    assert 'catalog.json' in results[0]
    assert 'catalog.Catalog' in results[0]
コード例 #18
0
def test_split_model_plans(
        tmp_path: pathlib.Path,
        sample_nist_component_def: component.ComponentDefinition) -> None:
    """Test for split_model method."""
    # Assume we are running a command like below
    # trestle split -f component-definition.yaml -e component-definition.metadata
    content_type = FileContentType.YAML

    # prepare trestle project dir with the file
    component_def_dir, component_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_nist_component_def,
        test_utils.COMPONENT_DEF_DIR)

    # read the model from file
    component_def = component.ComponentDefinition.oscal_read(
        component_def_file)
    element = Element(component_def)
    element_args = ['component-definition.metadata']
    element_paths = cmd_utils.parse_element_args(None, element_args)

    # extract values
    metadata_file = component_def_dir / element_paths[0].to_file_path(
        content_type)
    metadata = element.get_at(element_paths[0])

    root_file = component_def_dir / element_paths[0].to_root_path(content_type)
    remaining_root = element.get().stripped_instance(
        element_paths[0].get_element_name())

    # prepare the plan
    expected_plan = Plan()
    expected_plan.add_action(CreatePathAction(metadata_file))
    expected_plan.add_action(
        WriteFileAction(metadata_file, Element(metadata), content_type))
    expected_plan.add_action(CreatePathAction(root_file, True))
    expected_plan.add_action(
        WriteFileAction(root_file, Element(remaining_root), content_type))

    split_plan = SplitCmd.split_model(component_def, element_paths,
                                      component_def_dir, content_type, '',
                                      None)
    assert expected_plan == split_plan
コード例 #19
0
def test_add_failure(tmp_dir, sample_catalog_minimal):
    """Test AddCmd.add() method for trestle add."""
    content_type = FileContentType.JSON

    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_dir, content_type, sample_catalog_minimal, test_utils.CATALOGS_DIR)

    element_path = ElementPath('catalog.metadata.*')
    catalog_element = Element(sample_catalog_minimal)

    with pytest.raises(err.TrestleError):
        AddCmd.add(element_path, Catalog, catalog_element)

    element_path = ElementPath('catalog.metadata.title')
    with pytest.raises(err.TrestleError):
        AddCmd.add(element_path, Catalog, catalog_element)

    element_path = ElementPath('catalog.metadata.bad_path')
    with pytest.raises(err.TrestleError):
        AddCmd.add(element_path, Catalog, catalog_element)
コード例 #20
0
def test_striped_model(tmp_path, sample_catalog_minimal):
    """Test _run for AddCmd for stripped model."""
    cwd = os.getcwd()
    content_type = FileContentType.JSON
    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_catalog_minimal,
        test_utils.CATALOGS_DIR)
    os.chdir(catalog_def_dir)
    testargs = [
        'trestle', 'split', '-f', 'catalog.json', '-e', 'catalog.metadata'
    ]
    with patch.object(sys, 'argv', testargs):
        Trestle().run()

    # Now that the metadata has been split, add of catalog.metadata.roles will error,
    # but add of catalog.back-matter will pass

    testargs = [
        'trestle', 'add', '-f', 'catalog.json', '-e', 'catalog.metadata.roles'
    ]

    with patch.object(sys, 'argv', testargs):
        assert Trestle().run() == 1

    testargs = [
        'trestle', 'add', '-f', 'catalog.json', '-e', 'catalog.back-matter'
    ]

    current_model, _ = get_stripped_contextual_model()
    current_catalog = current_model.oscal_read(pathlib.Path('catalog.json'))
    current_catalog.back_matter = BackMatter()
    expected_catalog = current_catalog

    with patch.object(sys, 'argv', testargs):
        Trestle().run()

    actual_model, _ = get_stripped_contextual_model()
    actual_catalog = actual_model.oscal_read(pathlib.Path('catalog.json'))
    assert expected_catalog == actual_catalog

    os.chdir(cwd)
コード例 #21
0
def test_describe_failures(
    tmp_path: pathlib.Path, keep_cwd: pathlib.Path, sample_component_definition: ComponentDefinition
) -> None:
    """Test describe failure modes."""
    comp_def_dir, comp_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path,
        FileContentType.JSON,
        sample_component_definition,
        test_utils.COMPONENT_DEF_DIR)

    # not in trestle directory
    args = argparse.Namespace(
        file='comp_def.json', element='component-definition.metadata', verbose=1, trestle_root=tmp_path
    )
    assert DescribeCmd()._run(args) == 1

    os.chdir(comp_def_dir)

    # in trestle directory but have wildcard in element path
    args = argparse.Namespace(
        file=comp_def_file, element='component-definition.*.roles', verbose=1, trestle_root=tmp_path
    )
    assert DescribeCmd()._run(args) == 1

    # in trestle directory but have comma in element path
    args = argparse.Namespace(
        file=comp_def_file,
        element='component-definition.metadata,component-definition.back-matter',
        verbose=1,
        trestle_root=tmp_path
    )
    assert DescribeCmd()._run(args) == 1

    # in trestle directory but element only has one part
    args = argparse.Namespace(file=comp_def_file, element='component-definition', verbose=1, trestle_root=tmp_path)
    assert DescribeCmd()._run(args) == 1

    # no filename specified
    args = argparse.Namespace(file=None, element=None, trestle_root=tmp_path, verbose=1)
    assert DescribeCmd()._run(args) == 2
コード例 #22
0
def test_add_failure(tmp_path: pathlib.Path, sample_catalog_minimal: Catalog,
                     keep_cwd: pathlib.Path) -> None:
    """Test Add.add() method failures."""
    content_type = FileContentType.JSON

    _, _ = test_utils.prepare_trestle_project_dir(tmp_path, content_type,
                                                  sample_catalog_minimal,
                                                  test_utils.CATALOGS_DIR)

    element_path = ElementPath('catalog.metadata.*')
    catalog_element = Element(sample_catalog_minimal)

    with pytest.raises(err.TrestleError):
        Add.add(element_path, catalog_element, False)

    element_path = ElementPath('catalog.metadata.title')
    with pytest.raises(err.TrestleError):
        Add.add(element_path, catalog_element, False)

    element_path = ElementPath('catalog.metadata.bad_path')
    with pytest.raises(err.TrestleError):
        Add.add(element_path, catalog_element, False)
コード例 #23
0
def test_run(tmp_dir, sample_catalog_minimal):
    """Test _run for AddCmd."""
    # expected catalog after add of Responsible-Party
    file_path = pathlib.Path.joinpath(test_utils.JSON_TEST_DATA_PATH,
                                      'minimal_catalog_roles_double_rp.json')
    expected_catalog_roles2_rp = Catalog.oscal_read(file_path)

    content_type = FileContentType.YAML

    catalog_def_dir, catalog_def_file = test_utils.prepare_trestle_project_dir(
        tmp_dir, content_type, sample_catalog_minimal, test_utils.CATALOGS_DIR)

    testargs = [
        'trestle', 'add', '-f',
        str(catalog_def_file), '-e',
        'catalog.metadata.roles, catalog.metadata.roles, catalog.metadata.responsible-parties'
    ]

    with patch.object(sys, 'argv', testargs):
        Trestle().run()

    actual_catalog = Catalog.oscal_read(catalog_def_file)
    assert expected_catalog_roles2_rp == actual_catalog
コード例 #24
0
def test_split_model(tmp_dir, sample_target_def: ostarget.TargetDefinition):
    """Test for split_model method."""
    # Assume we are running a command like below
    # trestle split -f target-definition.yaml -e target-definition.metadata
    content_type = FileContentType.YAML

    # prepare trestle project dir with the file
    target_def_dir, target_def_file = test_utils.prepare_trestle_project_dir(
        tmp_dir, content_type, sample_target_def, test_utils.TARGET_DEFS_DIR)

    # read the model from file
    target_def = ostarget.TargetDefinition.oscal_read(target_def_file)
    element = Element(target_def)
    element_args = ['target-definition.metadata']
    element_paths = cmd_utils.parse_element_args(element_args)

    # extract values
    metadata_file = target_def_dir / element_paths[0].to_file_path(
        content_type)
    metadata = element.get_at(element_paths[0])

    root_file = target_def_dir / element_paths[0].to_root_path(content_type)
    remaining_root = element.get().stripped_instance(
        element_paths[0].get_element_name())

    # prepare the plan
    expected_plan = Plan()
    expected_plan.add_action(CreatePathAction(metadata_file))
    expected_plan.add_action(
        WriteFileAction(metadata_file, Element(metadata), content_type))
    expected_plan.add_action(CreatePathAction(root_file, True))
    expected_plan.add_action(
        WriteFileAction(root_file, Element(remaining_root), content_type))

    split_plan = SplitCmd.split_model(target_def, element_paths,
                                      target_def_dir, content_type)
    assert expected_plan == split_plan
コード例 #25
0
def test_split_multi_level_dict(
        tmp_path: pathlib.Path,
        sample_target_def: ostarget.TargetDefinition) -> None:
    """Test for split_model method."""
    # Assume we are running a command like below
    # trestle split -f target.yaml -e target-definition.targets.*.target-control-implementations.*

    content_type = FileContentType.YAML

    # prepare trestle project dir with the file
    target_def_dir, target_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_target_def, test_utils.TARGET_DEFS_DIR)

    file_ext = FileContentType.to_file_extension(content_type)

    # read the model from file
    target_def: ostarget.TargetDefinition = ostarget.TargetDefinition.oscal_read(
        target_def_file)
    element = Element(target_def)
    element_args = [
        'target-definition.targets.*.target-control-implementations.*'
    ]
    element_paths = test_utils.prepare_element_paths(target_def_dir,
                                                     element_args)

    expected_plan = Plan()

    # extract values
    targets: dict = element.get_at(element_paths[0])
    targets_dir = target_def_dir / element_paths[0].to_file_path()

    # split every targets
    for key in targets:
        # individual target dir
        target: ostarget.Target = targets[key]
        target_element = Element(targets[key])
        model_type = utils.classname_to_alias(type(target).__name__, 'json')
        dir_prefix = key
        target_dir_name = f'{dir_prefix}{const.IDX_SEP}{model_type}'
        target_file = targets_dir / f'{target_dir_name}{file_ext}'

        # target control impl dir for the target
        target_ctrl_impls: dict = target_element.get_at(element_paths[1])
        targets_ctrl_dir = targets_dir / element_paths[1].to_file_path(
            root_dir=target_dir_name)

        for i, target_ctrl_impl in enumerate(target_ctrl_impls):
            model_type = utils.classname_to_alias(
                type(target_ctrl_impl).__name__, 'json')
            file_prefix = str(i).zfill(const.FILE_DIGIT_PREFIX_LENGTH)
            file_name = f'{file_prefix}{const.IDX_SEP}{model_type}{file_ext}'
            file_path = targets_ctrl_dir / file_name
            expected_plan.add_action(CreatePathAction(file_path))
            expected_plan.add_action(
                WriteFileAction(file_path, Element(target_ctrl_impl),
                                content_type))

        # write stripped target model
        stripped_target = target.stripped_instance(
            stripped_fields_aliases=[element_paths[1].get_element_name()])
        expected_plan.add_action(CreatePathAction(target_file))
        expected_plan.add_action(
            WriteFileAction(target_file, Element(stripped_target),
                            content_type))

    root_file = target_def_dir / f'target-definition{file_ext}'
    remaining_root = element.get().stripped_instance(
        stripped_fields_aliases=[element_paths[0].get_element_name()])
    expected_plan.add_action(CreatePathAction(root_file, True))
    expected_plan.add_action(
        WriteFileAction(root_file, Element(remaining_root), content_type))

    split_plan = SplitCmd.split_model(target_def, element_paths,
                                      target_def_dir, content_type)
    assert expected_plan == split_plan
コード例 #26
0
def test_subsequent_split_model(
        tmp_path: pathlib.Path,
        sample_target_def: ostarget.TargetDefinition) -> None:
    """Test subsequent split of sub models."""
    # Assume we are running a command like below
    # trestle split -f target-definition.yaml -e target-definition.metadata

    content_type = FileContentType.YAML

    # prepare trestle project dir with the file
    target_def_dir, target_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_target_def, test_utils.TARGET_DEFS_DIR)

    # first split the target-def into metadata
    target_def = ostarget.TargetDefinition.oscal_read(target_def_file)
    element = Element(target_def, 'target-definition')
    element_args = ['target-definition.metadata']
    element_paths = test_utils.prepare_element_paths(target_def_dir,
                                                     element_args)
    metadata_file = target_def_dir / element_paths[0].to_file_path(
        content_type)
    metadata: ostarget.Metadata = element.get_at(element_paths[0])
    root_file = target_def_dir / element_paths[0].to_root_path(content_type)
    metadata_field_alias = element_paths[0].get_element_name()
    stripped_root = element.get().stripped_instance(
        stripped_fields_aliases=[metadata_field_alias])
    root_wrapper_alias = utils.classname_to_alias(
        stripped_root.__class__.__name__, 'json')

    first_plan = Plan()
    first_plan.add_action(CreatePathAction(metadata_file))
    first_plan.add_action(
        WriteFileAction(metadata_file, Element(metadata, metadata_field_alias),
                        content_type))
    first_plan.add_action(CreatePathAction(root_file, True))
    first_plan.add_action(
        WriteFileAction(root_file, Element(stripped_root, root_wrapper_alias),
                        content_type))
    first_plan.execute()  # this will split the files in the temp directory

    # now, prepare the expected plan to split metadta at parties
    second_plan = Plan()
    metadata_file_dir = target_def_dir / element_paths[0].to_root_path()
    metadata2 = ostarget.Metadata.oscal_read(metadata_file)
    element = Element(metadata2, metadata_field_alias)

    element_args = ['metadata.parties.*']
    element_paths = test_utils.prepare_element_paths(target_def_dir,
                                                     element_args)
    parties_dir = metadata_file_dir / element_paths[0].to_file_path()
    for i, party in enumerate(element.get_at(element_paths[0])):
        prefix = str(i).zfill(const.FILE_DIGIT_PREFIX_LENGTH)
        sub_model_actions = SplitCmd.prepare_sub_model_split_actions(
            party, parties_dir, prefix, content_type)
        second_plan.add_actions(sub_model_actions)

    # stripped metadata
    stripped_metadata = metadata2.stripped_instance(
        stripped_fields_aliases=['parties'])
    second_plan.add_action(CreatePathAction(metadata_file, True))
    second_plan.add_action(
        WriteFileAction(metadata_file,
                        Element(stripped_metadata, metadata_field_alias),
                        content_type))

    # call the split command and compare the plans
    split_plan = SplitCmd.split_model(metadata, element_paths,
                                      metadata_file_dir, content_type)
    assert second_plan == split_plan
コード例 #27
0
def test_split_multi_level_dict_plans(
        tmp_path: pathlib.Path,
        sample_nist_component_def: component.ComponentDefinition,
        keep_cwd) -> None:
    """Test for split_model method."""
    # Assume we are running a command like below
    # trestle split -f target.yaml -e component-definition.components.*.control-implementations.*

    content_type = FileContentType.YAML

    # prepare trestle project dir with the file
    component_def_dir, component_def_file = test_utils.prepare_trestle_project_dir(
        tmp_path, content_type, sample_nist_component_def,
        test_utils.COMPONENT_DEF_DIR)

    file_ext = FileContentType.to_file_extension(content_type)

    # read the model from file
    component_def: component.ComponentDefinition = component.ComponentDefinition.oscal_read(
        component_def_file)
    element = Element(component_def)
    element_args = [
        'component-definition.components.*.control-implementations.*'
    ]
    element_paths = cmd_utils.parse_element_args(
        None, element_args, component_def_dir.relative_to(tmp_path))

    expected_plan = Plan()

    # extract values
    components: list = element.get_at(element_paths[0])
    components_dir = component_def_dir / element_paths[0].to_file_path()

    # split every targets
    for index, comp_obj in enumerate(components):
        # individual target dir
        component_element = Element(comp_obj)
        model_type = str_utils.classname_to_alias(
            type(comp_obj).__name__, AliasMode.JSON)
        dir_prefix = str(index).zfill(const.FILE_DIGIT_PREFIX_LENGTH)
        component_dir_name = f'{dir_prefix}{const.IDX_SEP}{model_type}'
        component_file = components_dir / f'{component_dir_name}{file_ext}'

        # target control impl dir for the target
        component_ctrl_impls: list = component_element.get_at(element_paths[1])
        component_ctrl_dir = components_dir / element_paths[1].to_file_path(
            root_dir=component_dir_name)

        for i, component_ctrl_impl in enumerate(component_ctrl_impls):
            model_type = str_utils.classname_to_alias(
                type(component_ctrl_impl).__name__, AliasMode.JSON)
            file_prefix = str(i).zfill(const.FILE_DIGIT_PREFIX_LENGTH)
            file_name = f'{file_prefix}{const.IDX_SEP}{model_type}{file_ext}'
            file_path = component_ctrl_dir / file_name
            expected_plan.add_action(CreatePathAction(file_path))
            expected_plan.add_action(
                WriteFileAction(file_path, Element(component_ctrl_impl),
                                content_type))

        # write stripped target model
        stripped_target = comp_obj.stripped_instance(
            stripped_fields_aliases=[element_paths[1].get_element_name()])
        expected_plan.add_action(CreatePathAction(component_file))
        expected_plan.add_action(
            WriteFileAction(component_file, Element(stripped_target),
                            content_type))

    root_file = component_def_dir / f'component-definition{file_ext}'
    remaining_root = element.get().stripped_instance(
        stripped_fields_aliases=[element_paths[0].get_element_name()])
    expected_plan.add_action(CreatePathAction(root_file, True))
    expected_plan.add_action(
        WriteFileAction(root_file, Element(remaining_root), content_type))

    split_plan = SplitCmd.split_model(component_def, element_paths,
                                      component_def_dir, content_type, '',
                                      None)
    assert expected_plan == split_plan