-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(entrypoint): adds create-ssp entrypoint and tests
Signed-off-by: Jennifer Power <[email protected]>
- Loading branch information
Showing
3 changed files
with
162 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,8 +36,8 @@ | |
prepare_upstream_repo, | ||
setup_for_ssp, | ||
) | ||
from trestlebot.const import ERROR_EXIT_CODE, INVALID_ARGS_EXIT_CODE, SUCCESS_EXIT_CODE | ||
from trestlebot.tasks.authored.ssp import AuthoredSSP, SSPIndex | ||
from trestlebot.const import ERROR_EXIT_CODE, SUCCESS_EXIT_CODE | ||
from trestlebot.tasks.authored.ssp import SSPIndex | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
@@ -78,17 +78,6 @@ | |
ERROR_EXIT_CODE, | ||
True, | ||
), | ||
( | ||
"failure/missing args", | ||
{ | ||
"branch": "test", | ||
"oscal-model": "ssp", | ||
"committer-name": "test", | ||
"committer-email": "[email protected]", | ||
}, | ||
INVALID_ARGS_EXIT_CODE, | ||
False, | ||
), | ||
], | ||
) | ||
def test_ssp_editing_e2e( | ||
|
@@ -111,33 +100,40 @@ def test_ssp_editing_e2e( | |
tmp_repo_path = pathlib.Path(tmp_repo_str) | ||
|
||
args = setup_for_ssp(tmp_repo_path, test_prof, [test_comp_name], test_ssp_md) | ||
remote_url = "http://localhost:8080/test.git" | ||
repo.create_remote("origin", url=remote_url) | ||
|
||
# Create or generate the SSP | ||
if not skip_create: | ||
index_path = os.path.join(tmp_repo_str, "ssp-index.json") | ||
ssp_index = SSPIndex(index_path) | ||
authored_ssp = AuthoredSSP(tmp_repo_str, ssp_index) | ||
authored_ssp.create_new_default( | ||
create_args: Dict[str, str] = { | ||
"markdown-path": command_args["markdown-path"], | ||
"branch": command_args["branch"], | ||
"committer-name": command_args["committer-name"], | ||
"committer-email": command_args["committer-email"], | ||
"ssp-name": test_ssp_name, | ||
"profile-name": test_prof, | ||
"compdefs": test_comp_name, | ||
} | ||
command = build_test_command( | ||
tmp_repo_str, "create-ssp", create_args, image_name | ||
) | ||
run_response = subprocess.run(command, capture_output=True) | ||
assert run_response.returncode == response | ||
assert (tmp_repo_path / command_args["markdown-path"]).exists() | ||
|
||
# Make a change to the SSP | ||
ssp, ssp_path = ModelUtils.load_model_for_class( | ||
tmp_repo_path, | ||
test_ssp_name, | ||
test_prof, | ||
[test_comp_name], | ||
test_ssp_md, | ||
SystemSecurityPlan, | ||
FileContentType.JSON, | ||
) | ||
ssp.metadata.title = "New Title" | ||
ssp.oscal_write(ssp_path) | ||
else: | ||
ssp_generate = SSPGenerate() | ||
assert ssp_generate._run(args) == 0 | ||
|
||
ssp_path: pathlib.Path = ModelUtils.get_model_path_for_name_and_class( | ||
tmp_repo_path, | ||
test_ssp_name, | ||
SystemSecurityPlan, | ||
FileContentType.JSON, | ||
) | ||
assert not ssp_path.exists() | ||
|
||
remote_url = "http://localhost:8080/test.git" | ||
repo.create_remote("origin", url=remote_url) | ||
|
||
command = build_test_command(tmp_repo_str, "autosync", command_args, image_name) | ||
run_response = subprocess.run(command, capture_output=True) | ||
assert run_response.returncode == response | ||
|
@@ -151,8 +147,8 @@ def test_ssp_editing_e2e( | |
) | ||
|
||
# Check that the correct files are present with the correct content | ||
assert (tmp_repo_path / command_args["markdown-path"]).exists() | ||
ssp_index.reload() | ||
index_path = os.path.join(tmp_repo_str, "ssp-index.json") | ||
ssp_index = SSPIndex(index_path) | ||
assert ssp_index.get_profile_by_ssp(test_ssp_name) == test_prof | ||
assert ssp_index.get_comps_by_ssp(test_ssp_name) == [test_comp_name] | ||
assert ssp_index.get_leveraged_by_ssp(test_ssp_name) is None | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#!/usr/bin/python | ||
|
||
# SPDX-License-Identifier: Apache-2.0 | ||
# Copyright (c) 2024 Red Hat, Inc. | ||
|
||
""" | ||
Entrypoint for system security plan bootstrapping. | ||
This will create and initial SSP with markdown, an SSP index, and a SSP JSON file. | ||
""" | ||
|
||
import argparse | ||
import logging | ||
import pathlib | ||
from typing import List | ||
|
||
from trestlebot.entrypoints.entrypoint_base import EntrypointBase, comma_sep_to_list | ||
from trestlebot.entrypoints.log import set_log_level_from_args | ||
from trestlebot.tasks.assemble_task import AssembleTask | ||
from trestlebot.tasks.authored.ssp import AuthoredSSP, SSPIndex | ||
from trestlebot.tasks.base_task import ModelFilter, TaskBase | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class CreateSSPEntrypoint(EntrypointBase): | ||
"""Entrypoint for ssp bootstrapping.""" | ||
|
||
def __init__(self, parser: argparse.ArgumentParser) -> None: | ||
"""Initialize.""" | ||
super().__init__(parser) | ||
self.setup_create_ssp_arguments() | ||
|
||
def setup_create_ssp_arguments(self) -> None: | ||
"""Setup specific arguments for this entrypoint.""" | ||
self.parser.add_argument( | ||
"--ssp-name", required=True, type=str, help="Name of SSP to create." | ||
) | ||
self.parser.add_argument( | ||
"--profile-name", | ||
required=True, | ||
help="Name of profile in the trestle workspace to include in the SSP.", | ||
) | ||
self.parser.add_argument( | ||
"--compdefs", | ||
required=True, | ||
type=str, | ||
help="Comma-separated list of component definitions to include in the SSP", | ||
) | ||
self.parser.add_argument( | ||
"--leveraged-ssp", | ||
required=False, | ||
type=str, | ||
help="Provider SSP to leverage for the new SSP.", | ||
) | ||
self.parser.add_argument( | ||
"--markdown-path", | ||
required=True, | ||
type=str, | ||
help="Path to create markdown files in.", | ||
) | ||
self.parser.add_argument( | ||
"--yaml-header-path", | ||
required=False, | ||
type=str, | ||
help="Optionally set a path to a YAML file for custom SSP Markdown YAML headers.", | ||
) | ||
self.parser.add_argument( | ||
"--version", | ||
required=False, | ||
type=str, | ||
help="Optionally set the SSP version.", | ||
) | ||
self.parser.add_argument( | ||
"--ssp-index-path", | ||
required=False, | ||
type=str, | ||
default="ssp-index.json", | ||
help="Optionally set the path to the SSP index file.", | ||
) | ||
|
||
def run(self, args: argparse.Namespace) -> None: | ||
"""Run the entrypoint.""" | ||
|
||
set_log_level_from_args(args) | ||
|
||
# If the ssp index file does not exist, create it. | ||
ssp_index_path = pathlib.Path(args.ssp_index_path) | ||
if not ssp_index_path.exists(): | ||
# Create a parent directory | ||
ssp_index_path.parent.mkdir(parents=True, exist_ok=True) | ||
|
||
ssp_index = SSPIndex(args.ssp_index_path) | ||
authored_ssp = AuthoredSSP(args.working_dir, ssp_index) | ||
|
||
comps: List[str] = comma_sep_to_list(args.compdefs) | ||
authored_ssp.create_new_default( | ||
ssp_name=args.ssp_name, | ||
profile_name=args.profile_name, | ||
compdefs=comps, | ||
markdown_path=args.markdown_path, | ||
leveraged_ssp=args.leveraged_ssp, | ||
yaml_header=args.yaml_header_path, | ||
) | ||
|
||
# The starting point for SSPs in the markdown, so assemble into JSON. | ||
model_filter: ModelFilter = ModelFilter([], [args.ssp_name]) | ||
assemble_task = AssembleTask( | ||
authored_object=authored_ssp, | ||
markdown_dir=args.markdown_path, | ||
version=args.version, | ||
model_filter=model_filter, | ||
) | ||
pre_tasks: List[TaskBase] = [assemble_task] | ||
|
||
super().run_base(args, pre_tasks) | ||
|
||
|
||
def main() -> None: | ||
"""Run the CLI.""" | ||
parser = argparse.ArgumentParser( | ||
description="Create new system security plan for editing." | ||
) | ||
create_ssp = CreateSSPEntrypoint(parser=parser) | ||
|
||
args = parser.parse_args() | ||
create_ssp.run(args) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |