110 lines
3.3 KiB
Python
Executable File
110 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
from tqdm import tqdm
|
|
import jinja2
|
|
import yaml
|
|
import json
|
|
from os.path import splitext, join
|
|
from os import listdir
|
|
from datetime import date
|
|
|
|
OUTPUT_ROOT = "output/"
|
|
CCSA_DIR ="CCSA/"
|
|
HTML_OUTPUT_DIR = "html/"
|
|
RSS_FEED = "rss.xml"
|
|
JSON_CATALOG = "CCSA.json"
|
|
BASE_URL = "https://0x29a.codeberg.pages/CCSA-DEMO/"
|
|
|
|
ccsa_html_template = """<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Co-op Cloud Security Advisory (DEMO) {{ ccsa_id }}</title>
|
|
</head>
|
|
<body>
|
|
<article>
|
|
<h1>Co-op Cloud Security Advisory (DEMO) {{ ccsa_id }}</h1>
|
|
<p><b>Recipe:</b>: {{ recipe }}</p>
|
|
<p><b>Affected Versions:</b> {% for version in versions %}<br/>{{ version }}{% endfor %}</p>
|
|
<p><b>Affected Images:</b> {% for image in images %}<br/>{{ image }}{% endfor %}</p>
|
|
<p><b>Upgrade paths:</b> {% for upgrade in upgrade_paths %}<br/>{{ upgrade }}{% endfor %}</p>
|
|
<p><b>Description:</b><br/>{{ description }}</p>
|
|
</article>
|
|
</body>
|
|
</html>"""
|
|
|
|
|
|
ccsa_html_index_template = """<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Co-op Cloud Security Advisories</title>
|
|
</head>
|
|
<body>
|
|
<h1>Co-op Cloud Security Advisories</h1>
|
|
{% for ccsa in ccsas %}
|
|
<article>
|
|
<p><a href="{{ ccsa.ccsa_id }}.html">{{ ccsa.ccsa_id }}</a>: {{ ccsa.recipe }} {{ ccsa.short }}</p>
|
|
</article>
|
|
{% endfor %}
|
|
</body>
|
|
</html>"""
|
|
|
|
|
|
ccsa_rss_template = """<?xml version="1.0" encoding="utf-8"?>
|
|
<rss version="2.0">
|
|
<channel>
|
|
<title>Co-op Cloud Security Advisories (DEMO)</title>
|
|
<link>{{ base_url }}</link>
|
|
<description>Running feed of Security Advisories related to Co-op Cloud</description>
|
|
{% for ccsa in ccsas %}
|
|
<item>
|
|
<title>{{ ccsa.ccsa_id }}</title>
|
|
<link>{{ ccsa.url }}</link>
|
|
<description>{{ ccsa.recipe }} {{ ccsa.short }} {% for upgrade in ccsa.upgrade_paths %} <br/>{{ upgrade }} {% endfor %}</description>
|
|
<pubDate>{{ ccsa.date }}</pubDate>
|
|
</item>
|
|
{% endfor %}
|
|
</channel>
|
|
</rss>
|
|
"""
|
|
|
|
class ForceDateTimeEncoder(json.JSONEncoder):
|
|
def default(self, obj):
|
|
if isinstance(obj, date):
|
|
return str(obj)
|
|
return super().default(obj)
|
|
|
|
environment = jinja2.Environment()
|
|
html_template = environment.from_string(ccsa_html_template)
|
|
rss_template = environment.from_string(ccsa_rss_template)
|
|
index_template = environment.from_string(ccsa_html_index_template)
|
|
|
|
ccsas = []
|
|
print("parsing CCSAs and writing html advisories")
|
|
for f in tqdm(listdir(CCSA_DIR)):
|
|
ccsa_yml_path = join(CCSA_DIR, f)
|
|
with open(ccsa_yml_path) as fd:
|
|
ccsa = yaml.safe_load(fd.read())
|
|
ccsa["ccsa_id"] = splitext(f)[0]
|
|
html_file_name = f'{ccsa["ccsa_id"]}.html'
|
|
ccsa["url"] = f"{BASE_URL}/{html_file_name}"
|
|
ccsa["upgrade_paths"] = [f"{v} -> {u}" for v,u in zip(ccsa["versions"], ccsa["upgrade_to"])]
|
|
with open(join(OUTPUT_ROOT, html_file_name), "w") as fd:
|
|
fd.write(html_template.render(base_url=BASE_URL, **ccsa))
|
|
ccsas.append(ccsa)
|
|
|
|
print("creating RSS feed")
|
|
with open(join(OUTPUT_ROOT, RSS_FEED), "w") as fd:
|
|
fd.write(rss_template.render(base_url=BASE_URL, ccsas=ccsas))
|
|
|
|
print("creating json catalog")
|
|
with open(join(OUTPUT_ROOT, JSON_CATALOG), "w") as fd:
|
|
fd.write(json.dumps(ccsas, cls=ForceDateTimeEncoder))
|
|
|
|
print("creating index")
|
|
with open(join(OUTPUT_ROOT, "index.html"), "w") as fd:
|
|
fd.write(index_template.render(ccsas=ccsas))
|
|
|
|
print("complete")
|