diff --git a/Dockerfile b/Dockerfile index 5541b835..fe3d119d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,16 +20,21 @@ RUN dnf -y --setopt=tsflags=nodocs install \ jq \ python39-devel \ diffutils \ + python39-pip \ python39-requests \ skopeo \ krb5-workstation \ && dnf clean all +RUN pip3 install jinja2 \ + jinja2-ansible-filters + ADD data/certs/2015-IT-Root-CA.pem data/certs/2022-IT-Root-CA.pem /etc/pki/ca-trust/source/anchors/ RUN update-ca-trust COPY pyxis /home/pyxis COPY utils /home/utils +COPY templates /home/templates # Set HOME variable to something else than `/` to avoid 'permission denied' problems when writing files. ENV HOME=/tekton/home diff --git a/requirements.txt b/requirements.txt index 547de5c5..ec986676 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ pytest requests +jinja2 +jinja2-ansible-filters diff --git a/templates/advisory.yaml.jinja b/templates/advisory.yaml.jinja new file mode 100644 index 00000000..e8c2faaf --- /dev/null +++ b/templates/advisory.yaml.jinja @@ -0,0 +1,23 @@ +apiVersion: rhtap.redhat.com/v1alpha1 +kind: Advisory +metadata: + name: {{ advisory_name }} +spec: + product_id: {{ advisory.spec.product_id }} + cpe: {{ advisory.spec.cpe }} + type: {{ advisory.spec.type }} +{%- if 'issues' in advisory.spec %} + issues: + {{ advisory.spec.issues | to_nice_yaml(indent=2) | indent(4) | trim }} +{%- endif %} + content: + {{ advisory.spec.content | to_nice_yaml(indent=2) | indent(4) | trim }} + synopsis: {{ advisory.spec.synopsis }} + topic: >- + {{ advisory.spec.topic | wordwrap(76) | indent(4) }} + description: >- + {{ advisory.spec.description | wordwrap(76) | indent(4) }} + solution: >- + {{ advisory.spec.solution | wordwrap(76) | indent(4) }} + references: + {{ advisory.spec.references | to_nice_yaml | indent(4) }} diff --git a/utils/apply_template.py b/utils/apply_template.py new file mode 100755 index 00000000..8500abab --- /dev/null +++ b/utils/apply_template.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +from jinja2 import Template +from jinja2_ansible_filters import AnsibleCoreFiltersExtension +import argparse +import json + + +def setup_argparser() -> argparse.Namespace: # pragma: no cover + """Setup argument parser + + :return: Initialized argument parser + """ + + parser = argparse.ArgumentParser(description="Applies a template.") + + parser.add_argument( + "--data", + help="JSON string containing data to use in the template.", + required=True, + ) + parser.add_argument( + "--template", + help="Path to the template file to use.", + required=True, + ) + parser.add_argument( + "-o", + "--output", + help="The desired filename of the result.", + required=True, + ) + return parser.parse_args() + + +def main(): # pragma: no cover + """Main func""" + + args = setup_argparser() + + with open(args.template) as t: + template = Template(t.read(), extensions=[AnsibleCoreFiltersExtension]) + content = template.render(json.loads(args.data)) + + filename = args.output + with open(filename, mode="w", encoding="utf-8") as advisory: + advisory.write(content) + print(f"Wrote {filename}") + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/utils/test_apply_template.py b/utils/test_apply_template.py new file mode 100644 index 00000000..911ef960 --- /dev/null +++ b/utils/test_apply_template.py @@ -0,0 +1,44 @@ +import pytest +from unittest.mock import patch, MagicMock +from apply_template import setup_argparser, main + + +@patch( + "argparse._sys.argv", + ["apply_template", "--data", "{}", "--template", "somefile", "-o", "newfile"], +) +def test_setup_argparser_proper_args(): + args_out = setup_argparser() + assert args_out.data == "{}" + assert args_out.template == "somefile" + assert args_out.output == "newfile" + + +def test_setup_argparser_improper_args(): + with pytest.raises(SystemExit) as e: + setup_argparser() + assert e.value.code == 2 + + +@patch("builtins.open") +@patch("apply_template.Template.render") +@patch("apply_template.setup_argparser") +def test_apply_template_advisory_template( + mock_argparser: MagicMock, mock_render: MagicMock, mock_open: MagicMock +): + args = MagicMock() + args.template = "templates/advisory.yaml.jinja" + args.data = "{}" + args.output = "somefile" + mock_argparser.return_value = args + mock_render.return_value = "applied template file" + mock_open1 = MagicMock() + mock_open2 = MagicMock() + mock_open.side_effect = [mock_open1, mock_open2] + mock_open1.__enter__.return_value.read.side_effect = "foo: bar" + file = mock_open2.__enter__.return_value + + # Act + main() + + file.write.assert_called_once_with("applied template file")