Skip to content

Commit

Permalink
feat(infra): multiple actions
Browse files Browse the repository at this point in the history
- Consolidates multiple trestle-bot entrypoints within the
published trestle-bot image.
- Adds multiple gh-actions to trestle-bot.

Related PSCE-243, PSCE-248

Majority of code generated by chatGPT
Signed-off-by: Alex Flom <[email protected]>
  • Loading branch information
afflom committed Oct 10, 2023
1 parent c689a2f commit 19f686f
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ RUN microdnf install -y git \
&& rm -rf /var/lib/apt/lists/*

COPY ./entrypoint.sh /
COPY ./trestlebot/infra/entrypoints/* /entrypoints/

RUN chmod +x /entrypoint.sh
RUN for f in /entrypoints/*; do chmod +x $f; done

ENTRYPOINT ["python3.9", "-m" , "trestlebot"]
CMD ["--help"]
Expand Down
78 changes: 78 additions & 0 deletions actions/create-ssp/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: "trestle-bot-create-ssp"
author: "Red Hat Product Security"
description: "Creates a new SSP with trestle-bot, a workflow automation manager for OSCAL formatted compliance content"

inputs:
verbose:
description: "Enable verbose mode"
required: false
default: "false"
branch:
description: "Branch name to push changes to"
required: true
working_dir:
description: "Working directory with git repository"
required: false
default: "."
file_patterns:
description: "Comma-separated list of file patterns to be used with `git add` in repository updates"
required: true
commit_message:
description: "Commit message for automated updates"
required: false
default: "chore: automatic updates"
pull_request_title:
description: "Customized title for submitted pull requests"
required: false
default: "Automatic updates from trestlebot"
committer_name:
description: "Name of committer"
required: true
committer_email:
description: "Email for committer"
required: true
author_name:
description: "Name for commit author if differs from committer"
required: false
author_email:
description: "Email for commit author if differs from committer"
required: false
target_branch:
description: "Target branch or base branch to create a pull request against. No pull request is created if unset"
required: false
with_token:
description: "Read token from standard input for authenticated requests with Git provider (e.g. create pull requests)"
required: false
ssp_name:
description: "Name of the SSP to create."
required: true
profile_name:
description: "Name of the profile to use."
required: true
compdefs:
description: "Component definitions to include."
required: true
leveraged_ssp:
description: "Leveraged SSP."
required: false
filtered_ssp:
description: "Filtered SSP."
required: false
outputs:
changes:
description: Value is "true" if changes were committed back to the repository.
commit:
description: Full hash of the created commit. Only present if the "changes" output is "true".
pr_number:
description: Number of the submitted pull request. Only present if a pull request is submitted.

runs:
using: "docker"
image: "quay.io/continuouscompliance/trestlebot:latest"
entrypoint: "/entrypoints/create_ssp.py"
env:
GITHUB_TOKEN: ${{ inputs.github_token }}

branding:
icon: "check"
color: "green"
2 changes: 1 addition & 1 deletion actions/trestle-bot/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ outputs:

runs:
using: "docker"
image: "Dockerfile"
image: "quay.io/continuouscompliance/trestlebot:latest"
entrypoint: "/entrypoint.sh"
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
Expand Down
75 changes: 75 additions & 0 deletions tests/trestlebot/entrypoints/test_create_ssp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
import argparse
from unittest import mock
import pytest

from trestlebot.infra.entrypoints.create_ssp import CreateNewSSP
from tests.conftest import tmp_trestle_dir, tmp_repo # Replace with the actual import

@pytest.fixture
def mock_args():
args = argparse.Namespace()
args.ssp_name = "test_ssp"
args.profile_name = "test_profile"
args.compdefs = "comp1,comp2"
args.leveraged_ssp = None
args.trestle_root = "."
args.ssp_index = "ssp-index.json"
args.filtered_ssp = None
return args

@pytest.mark.usefixtures("tmp_trestle_dir", "tmp_repo")
def test_run_success(mock_args, tmp_trestle_dir, tmp_repo):
with mock.patch('create_new_ssp.AuthoredSSP') as MockAuthoredSSP, \
mock.patch('create_new_ssp.SSPIndex') as MockSSPIndex, \
mock.patch('create_new_ssp.comma_sep_to_list', return_value=['comp1', 'comp2']):

mock_authored_ssp_instance = MockAuthoredSSP.return_value
mock_ssp_index_instance = MockSSPIndex.return_value

parser = argparse.ArgumentParser()
create_new_ssp = CreateNewSSP(parser)
create_new_ssp.run(mock_args)

MockSSPIndex.assert_called_once_with("ssp-index.json")
MockAuthoredSSP.assert_called_once_with(".", mock_ssp_index_instance)
mock_authored_ssp_instance.create_new_default.assert_called_once_with(
"test_ssp", "test_profile", ['comp1', 'comp2'], "markdown/system-security-plans", None
)

@pytest.mark.usefixtures("tmp_trestle_dir", "tmp_repo")
def test_run_with_filter(mock_args, tmp_trestle_dir, tmp_repo):
mock_args.filtered_ssp = "filtered_ssp"
with mock.patch('create_new_ssp.AuthoredSSP') as MockAuthoredSSP, \
mock.patch('create_new_ssp.SSPIndex') as MockSSPIndex, \
mock.patch('create_new_ssp.comma_sep_to_list', return_value=['comp1', 'comp2']):

mock_authored_ssp_instance = MockAuthoredSSP.return_value
mock_ssp_index_instance = MockSSPIndex.return_value

parser = argparse.ArgumentParser()
create_new_ssp = CreateNewSSP(parser)
create_new_ssp.run(mock_args)

MockSSPIndex.assert_called_once_with("ssp-index.json")
MockAuthoredSSP.assert_called_once_with(".", mock_ssp_index_instance)
mock_authored_ssp_instance.create_new_with_filter.assert_called_once_with(
"test_ssp", "filtered_ssp", "test_profile", ['comp1', 'comp2']
)

@pytest.mark.usefixtures("tmp_trestle_dir", "tmp_repo")
def test_run_exception(mock_args, tmp_trestle_dir, tmp_repo):
with mock.patch('create_new_ssp.AuthoredSSP') as MockAuthoredSSP, \
mock.patch('create_new_ssp.SSPIndex') as MockSSPIndex, \
mock.patch('create_new_ssp.comma_sep_to_list', return_value=['comp1', 'comp2']), \
mock.patch('create_new_ssp.handle_exception') as mock_handle_exception, \
mock.patch('sys.exit') as mock_exit:

MockAuthoredSSP.side_effect = Exception("Some error")

parser = argparse.ArgumentParser()
create_new_ssp = CreateNewSSP(parser)
create_new_ssp.run(mock_args)

mock_handle_exception.assert_called_once()
mock_exit.assert_called_once_with(1)
31 changes: 0 additions & 31 deletions trestlebot/infra/entrypoints/create.py

This file was deleted.

56 changes: 56 additions & 0 deletions trestlebot/infra/entrypoints/create_ssp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# create_new_ssp.py

import argparse
import sys

from trestlebot.tasks.authored.ssp import AuthoredSSP, SSPIndex
from trestlebot.cli import comma_sep_to_list
from trestlebot.cli_base import EntrypointBase, handle_exception


class CreateNewSSP(EntrypointBase):
def __init__(self, parser: argparse.ArgumentParser) -> None:
super().__init__(parser)
self.setup_specific_arguments()

def setup_specific_arguments(self) -> None:
self.parser.add_argument("--ssp_name", required=True)
self.parser.add_argument("--profile_name", required=True)
self.parser.add_argument("--compdefs", required=True)
self.parser.add_argument("--leveraged_ssp", required=False)
self.parser.add_argument("--trestle_root", required=False, default=".")
self.parser.add_argument("--ssp_index", required=False, default="ssp-index.json")
self.parser.add_argument("--filtered_ssp", required=False)

def run(self, args: argparse.Namespace) -> None:
try:
ssp_index = SSPIndex(args.ssp_index)
authored_ssp = AuthoredSSP(args.trestle_root, ssp_index)

comps = comma_sep_to_list(args.compdefs)
if args.filtered_ssp:
authored_ssp.create_new_with_filter(
args.ssp_name,
args.filtered_ssp,
args.profile_name,
comps
)
else:
authored_ssp.create_new_default(
args.ssp_name,
args.profile_name,
comps,
"markdown/system-security-plans",
args.leveraged_ssp
)
except Exception as e:
handle_exception(e, "Failed to create new SSP")
sys.exit(1)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Create a default ssp")
entrypoint = CreateNewSSP(parser)
args = parser.parse_args()
entrypoint.run(args)

0 comments on commit 19f686f

Please sign in to comment.