Data Sources: {{ parsed.datasources_list_len }}
{{row.name}}
|
+
+ {% for dom in row.domains %}
+ {{dom}}
+
+ {% endfor %}
+ |
{% if row.deprecated %}
****Deprecation Warning****
diff --git a/modules/groups/groups.py b/modules/groups/groups.py
index 0de9fdf4f93..5b2c888bd6c 100644
--- a/modules/groups/groups.py
+++ b/modules/groups/groups.py
@@ -65,11 +65,6 @@ def generate_markdown_files():
side_menu_data = util.buildhelpers.get_side_menu_data("Groups", "/groups/", group_list_no_deprecated_revoked)
data["side_menu_data"] = side_menu_data
- side_menu_mobile_view_data = util.buildhelpers.get_side_menu_mobile_view_data(
- "groups", "/groups/", group_list_no_deprecated_revoked, group_by
- )
- data["side_menu_mobile_view_data"] = side_menu_mobile_view_data
-
data["groups_table"] = get_groups_table_data(group_list_no_deprecated_revoked)
data["groups_list_len"] = str(len(group_list_no_deprecated_revoked))
@@ -80,12 +75,12 @@ def generate_markdown_files():
# Create the markdown for the enterprise groups in the STIX
for group in group_list:
- generate_group_md(group, side_menu_data, side_menu_mobile_view_data, notes)
+ generate_group_md(group, side_menu_data, notes)
return has_group
-def generate_group_md(group, side_menu_data, side_menu_mobile_view_data, notes):
+def generate_group_md(group, side_menu_data, notes):
"""Responsible for generating markdown of all groups"""
attack_id = util.buildhelpers.get_attack_id(group)
@@ -94,9 +89,7 @@ def generate_group_md(group, side_menu_data, side_menu_mobile_view_data, notes):
data = {}
data["attack_id"] = attack_id
-
data["side_menu_data"] = side_menu_data
- data["side_menu_mobile_view_data"] = side_menu_mobile_view_data
data["notes"] = notes.get(group["id"])
# External references
diff --git a/modules/groups/templates/group.html b/modules/groups/templates/group.html
index f072503aa69..c2247770c39 100644
--- a/modules/groups/templates/group.html
+++ b/modules/groups/templates/group.html
@@ -27,12 +27,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/groups/templates/groups-index.html b/modules/groups/templates/groups-index.html
index abea03bc3d6..382d907dd7a 100644
--- a/modules/groups/templates/groups-index.html
+++ b/modules/groups/templates/groups-index.html
@@ -7,12 +7,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/mitigations/mitigations.py b/modules/mitigations/mitigations.py
index 06a8b91b130..e6e6eb64e3c 100644
--- a/modules/mitigations/mitigations.py
+++ b/modules/mitigations/mitigations.py
@@ -45,13 +45,11 @@ def generate_mitigations():
notes = util.relationshipgetters.get_objects_using_notes()
side_nav_data = util.buildhelpers.get_side_nav_domains_data("mitigations", mitigations)
- side_nav_mobile_data = util.buildhelpers.get_side_nav_domains_mobile_view_data("mitigations", mitigations, group_by)
-
for domain in site_config.domains:
if domain["deprecated"]:
continue
check_if_generated = generate_markdown_files(
- domain["name"], mitigations_with_deprecated[domain["name"]], side_nav_data, side_nav_mobile_data, notes
+ domain["name"], mitigations_with_deprecated[domain["name"]], side_nav_data, notes
)
if not mitigation_generated:
if check_if_generated:
@@ -61,7 +59,7 @@ def generate_mitigations():
util.buildhelpers.remove_module_from_menu(mitigations_config.module_name)
-def generate_markdown_files(domain, mitigations, side_nav_data, side_nav_mobile_data, notes):
+def generate_markdown_files(domain, mitigations, side_nav_data, notes):
"""Responsible for generating shared data between all mitigation pages and begins mitigation markdown generation."""
data = {}
@@ -72,7 +70,6 @@ def generate_markdown_files(domain, mitigations, side_nav_data, side_nav_mobile_
]
data["mitigation_list_len"] = str(len(non_deprecated_mitigations))
data["side_menu_data"] = side_nav_data
- data["side_menu_mobile_view_data"] = side_nav_mobile_data
data["mitigation_table"] = get_mitigation_table_data(non_deprecated_mitigations)
@@ -85,7 +82,7 @@ def generate_markdown_files(domain, mitigations, side_nav_data, side_nav_mobile_
# Generates the markdown files to be used for page generation
for mitigation in mitigations:
- generate_mitigation_md(mitigation, domain, side_nav_data, side_nav_mobile_data, notes)
+ generate_mitigation_md(mitigation, domain, side_nav_data, notes)
return True
@@ -93,7 +90,7 @@ def generate_markdown_files(domain, mitigations, side_nav_data, side_nav_mobile_
return False
-def generate_mitigation_md(mitigation, domain, side_menu_data, side_menu_mobile_data, notes):
+def generate_mitigation_md(mitigation, domain, side_menu_data, notes):
"""Generates the markdown for the given mitigation"""
attack_id = util.buildhelpers.get_attack_id(mitigation)
@@ -104,7 +101,6 @@ def generate_mitigation_md(mitigation, domain, side_menu_data, side_menu_mobile_
data["domain"] = domain.split("-")[0]
data["side_menu_data"] = side_menu_data
- data["side_menu_mobile_view_data"] = side_menu_mobile_data
data["name"] = mitigation["name"]
data["notes"] = notes.get(mitigation["id"])
diff --git a/modules/mitigations/templates/mitigation.html b/modules/mitigations/templates/mitigation.html
index a7edc6649bc..95515399a6a 100644
--- a/modules/mitigations/templates/mitigation.html
+++ b/modules/mitigations/templates/mitigation.html
@@ -26,12 +26,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/mitigations/templates/mitigations-domain-index.html b/modules/mitigations/templates/mitigations-domain-index.html
index ca21e016fae..509ead41ec5 100644
--- a/modules/mitigations/templates/mitigations-domain-index.html
+++ b/modules/mitigations/templates/mitigations-domain-index.html
@@ -14,12 +14,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/resources/docs/attack_matrix_poster_2023_april.pdf b/modules/resources/docs/attack_matrix_poster_2023_april.pdf
new file mode 100644
index 00000000000..e4d3ffcce24
Binary files /dev/null and b/modules/resources/docs/attack_matrix_poster_2023_april.pdf differ
diff --git a/modules/resources/docs/attack_roadmap_2022_october.pdf b/modules/resources/docs/attack_roadmap_2022_october.pdf
new file mode 100644
index 00000000000..e49680f65a5
Binary files /dev/null and b/modules/resources/docs/attack_roadmap_2022_october.pdf differ
diff --git a/modules/resources/templates/resources.html b/modules/resources/templates/resources.html
index 17abc1986d3..bab4d488e9b 100644
--- a/modules/resources/templates/resources.html
+++ b/modules/resources/templates/resources.html
@@ -110,18 +110,18 @@ Graphics
-
+
-
+
diff --git a/modules/software/software.py b/modules/software/software.py
index 73a9654b2b4..b93a6faee0b 100644
--- a/modules/software/software.py
+++ b/modules/software/software.py
@@ -55,12 +55,8 @@ def generate_markdown_files():
side_menu_data = util.buildhelpers.get_side_menu_data(
"software", "/software/", software_list_no_deprecated_revoked
)
- side_menu_mobile_view_data = util.buildhelpers.get_side_menu_mobile_view_data(
- "software", "/software/", software_list_no_deprecated_revoked, group_by
- )
-
+
data["side_menu_data"] = side_menu_data
- data["side_menu_mobile_view_data"] = side_menu_mobile_view_data
data["software_table"] = get_software_table_data(software_list_no_deprecated_revoked)
subs = software_config.software_index_md + json.dumps(data)
@@ -69,12 +65,12 @@ def generate_markdown_files():
# Create the markdown for the enterprise groups in the stix
for software in software_list:
- generate_software_md(software, side_menu_data, side_menu_mobile_view_data, notes)
+ generate_software_md(software, side_menu_data, notes)
return has_software
-def generate_software_md(software, side_menu_data, side_menu_mobile_view_data, notes):
+def generate_software_md(software, side_menu_data, notes):
"""Responsible for generating given software markdown"""
attack_id = util.buildhelpers.get_attack_id(software)
@@ -85,7 +81,6 @@ def generate_software_md(software, side_menu_data, side_menu_mobile_view_data, n
data["attack_id"] = attack_id
data["side_menu_data"] = side_menu_data
- data["side_menu_mobile_view_data"] = side_menu_mobile_view_data
data["notes"] = notes.get(software["id"])
dates = util.buildhelpers.get_created_and_modified_dates(software)
diff --git a/modules/software/templates/software-index.html b/modules/software/templates/software-index.html
index 9b7ffe7ee4b..573481e8c33 100644
--- a/modules/software/templates/software-index.html
+++ b/modules/software/templates/software-index.html
@@ -7,12 +7,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/software/templates/software.html b/modules/software/templates/software.html
index 324661ce109..0e1275cf6e0 100644
--- a/modules/software/templates/software.html
+++ b/modules/software/templates/software.html
@@ -21,12 +21,9 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
-
- {{ navigation.sidenav(parsed.side_menu_mobile_view_data, output_file) }}
-
{% endblock %}
diff --git a/modules/tactics/templates/tactic.html b/modules/tactics/templates/tactic.html
index 1fcd435aa76..5ae8e3aa715 100644
--- a/modules/tactics/templates/tactic.html
+++ b/modules/tactics/templates/tactic.html
@@ -25,7 +25,7 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
diff --git a/modules/tactics/templates/tactics-domain-index.html b/modules/tactics/templates/tactics-domain-index.html
index 2282c5a3b88..ab231368b91 100644
--- a/modules/tactics/templates/tactics-domain-index.html
+++ b/modules/tactics/templates/tactics-domain-index.html
@@ -23,7 +23,7 @@
{% block innerleft %}
-
+
{{ navigation.sidenav(parsed.side_menu_data, output_file) }}
diff --git a/modules/util/buildhelpers.py b/modules/util/buildhelpers.py
index 5751d5ecd3d..ea0c6eb92ab 100644
--- a/modules/util/buildhelpers.py
+++ b/modules/util/buildhelpers.py
@@ -100,6 +100,11 @@ def get_attack_id(object):
return None
+def get_domain_name(object):
+ """Given an object, return domains."""
+ return object.get("x_mitre_domains")
+
+
def update_reference_list(reference_list, obj):
"""Given a reference list and an object, update the reference list with the external references found in the object."""
if obj.get("external_references"):
@@ -289,101 +294,6 @@ def get_element_data(element):
}
-def get_side_nav_domains_mobile_view_data(side_nav_title, elements_list, amount_per_row):
- """Given a title, an elements list and the amount of elements per row, get the data for the side navigation on a mobile view."""
-
- def get_element_data(element):
- """Given an element, return the formatted JSON."""
- return {
- "name": element["name"],
- "id": uuid.uuid4().hex,
- "path": "/{}/{}/".format(side_nav_title, attack_id),
- "children": [],
- }
-
- def check_children(category_list, domain_list):
- """Given a category list, check if there is no children and update list. Ignore if is digits or other."""
- for cat in category_list:
- if not cat["children"]:
- if cat["name"].startswith("1"):
- continue
- elif cat["name"].startswith("Other"):
- continue
- else:
- # Add empty child
- child = {"name": "No {}".format(side_nav_title), "id": "empty", "path": None, "children": []}
- cat["children"].append(child)
- domain_data["children"].append(cat)
-
- return domain_data
-
- def get_category_list():
- """Get an empty category list."""
- caterogories_content = []
- for cat in categories:
- pane = {"name": cat, "id": uuid.uuid4().hex, "path": None, "children": []}
- caterogories_content.append(pane)
-
- return caterogories_content
-
- categories_map = {char: math.ceil((i + 1) / amount_per_row) for i, char in enumerate(string.ascii_uppercase)}
- categories = list(
- map(
- lambda cat: cat[0] + "-" + cat[-1],
- [
- string.ascii_uppercase[i : i + amount_per_row]
- for i in range(0, len(string.ascii_uppercase), amount_per_row)
- ],
- )
- )
- categories = ["1-9"] + categories + ["Other"]
-
- elements_data = []
-
- for domain in site_config.domains:
- if domain["deprecated"]:
- continue
- if elements_list[domain["name"]]:
- caterogy_list = get_category_list()
-
- domain_data = {
- "name": domain["alias"],
- "id": domain["alias"],
- "path": "/{}/{}/".format(side_nav_title, domain["name"].split("-")[0]),
- "children": [],
- }
-
- for element in elements_list[domain["name"]]:
- attack_id = get_attack_id(element)
- if attack_id:
- child = get_element_data(element)
-
- # Get first character and find in map
- element_char = element["name"][0]
-
- if element_char.isdigit():
- element_cat_index = 0
- elif element_char.isalpha():
- element_cat_index = categories_map[element_char.upper()]
- else:
- element_cat_index = len(categories) - 1
-
- # Add child to pane
- caterogy_list[element_cat_index]["children"].append(child)
-
- domain_data = check_children(caterogy_list, domain_data)
-
- elements_data.append(domain_data)
-
- # return side menu
- return {
- "name": side_nav_title,
- "id": side_nav_title,
- "path": None, # root level doesn't get a path
- "children": elements_data,
- }
-
-
def get_side_menu_data(side_nav_title, path_prefix, elements_list, domain=None):
"""Responsible for generating the links that are located on the left side of pages for desktop clients."""
@@ -412,79 +322,6 @@ def get_side_menu_data(side_nav_title, path_prefix, elements_list, domain=None):
}
-def get_side_menu_mobile_view_data(side_nav_title, path_prefix, elements_list, amount_per_row, domain=None):
- """Responsible for generating the links that are located on the left side of pages for mobile devices."""
- categories_map = {char: math.ceil((i + 1) / amount_per_row) for i, char in enumerate(string.ascii_uppercase)}
- categories = list(
- map(
- lambda cat: cat[0] + "-" + cat[-1],
- [
- string.ascii_uppercase[i : i + amount_per_row]
- for i in range(0, len(string.ascii_uppercase), amount_per_row)
- ],
- )
- )
- categories = ["1-9"] + categories + ["Other"]
-
- mobile_side_table_data = []
-
- caterogories_content = []
- for cat in categories:
- pane = {"name": cat, "id": uuid.uuid4().hex, "path": None, "children": []}
- caterogories_content.append(pane)
-
- for element in elements_list:
- # Fill rows for each category
- attack_id = get_attack_id(element)
-
- if attack_id:
- child = {
- "name": element["name"],
- "id": uuid.uuid4().hex,
- "path": path_prefix + attack_id + "/",
- "children": [],
- }
-
- # Get first character and find in map
- element_char = element["name"][0]
-
- if element_char.isdigit():
- element_cat_index = 0
- elif element_char.isalpha():
- element_cat_index = categories_map[element_char.upper()]
- else:
- element_cat_index = len(categories) - 1
-
- # Add child to pane
- caterogories_content[element_cat_index]["children"].append(child)
-
- # Add categories to mobile side navigation
- # Remove "1-9" and "Other" categories if empty
- # Add "No [Type]" to empty object, side_nav_title will hold the type of the page
-
- for cat in caterogories_content:
- if not cat["children"]:
- if cat["name"].startswith("1"):
- continue
- elif cat["name"].startswith("Other"):
- continue
- else:
- # Add empty child
- child = {"name": "No {}".format(side_nav_title), "id": "empty", "path": None, "children": []}
- cat["children"].append(child)
- mobile_side_table_data.append(cat)
-
- if domain:
- path_prefix += domain + "/"
- # return side menu
- return {
- "name": side_nav_title,
- "id": side_nav_title,
- "path": path_prefix, # root level doesn't get a path
- "children": mobile_side_table_data,
- }
-
-
def is_tid(tid):
"""Check if input has a tid pattern."""
pattern = re.compile("^T[0-9][0-9][0-9][0-9]$")
diff --git a/modules/website_build/website_build.py b/modules/website_build/website_build.py
index 4af3d0076f9..1270d672d3c 100644
--- a/modules/website_build/website_build.py
+++ b/modules/website_build/website_build.py
@@ -2,7 +2,7 @@
import os
import shutil
import subprocess
-import uuid
+import hashlib
from string import Template
from loguru import logger
@@ -43,6 +43,25 @@ def generate_website():
remove_unwanted_output()
+def generate_uuid_from_seeds(content_version, website_version):
+ """
+ Generate a UUID based on the given content_version and website_version.
+
+ Args:
+ - content_version (str): Semantic version of the content without a leading 'v'.
+ - website_version (str): Semantic version of the website with a leading 'v'.
+
+ Returns:
+ - str: A UUID generated based on the two versions.
+ """
+ # Combine and hash the values
+ seed = f"{content_version}-{website_version}".encode('utf-8')
+ hashed_seed = hashlib.md5(seed).hexdigest()
+
+ # Convert the first 32 characters of the hash to a UUID format
+ return '-'.join([hashed_seed[i:i+length] for i, length in zip([0, 8, 12, 16, 20], [8, 4, 4, 4, 12])])
+
+
def generate_javascript_settings():
"""Creates javascript settings file that will be used to other javascript files"""
logger.info("Generating JavaScript settings.js")
@@ -70,7 +89,13 @@ def generate_javascript_settings():
web_dir = web_dir + "/"
js_data = website_build_config.js_dir_settings.substitute({"web_directory": web_dir})
- build_uuid = str(uuid.uuid4())
+
+ # Use the content and website versions as a seed for the build UUID to ensure that the UUID is idempotent.
+ CONTENT_VERSION = website_build_config.base_page_data['CONTENT_VERSION']
+ WEBSITE_VERSION = website_build_config.base_page_data['WEBSITE_VERSION']
+
+ build_uuid = generate_uuid_from_seeds(CONTENT_VERSION, WEBSITE_VERSION)
+
js_build_uuid = website_build_config.js_build_uuid.substitute({"build_uuid": build_uuid})
js_data += js_build_uuid
js_f.write(js_data)
diff --git a/pyproject.toml b/pyproject.toml
index c478333cfdb..af04b688a95 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ profile = "black"
[tool.towncrier]
name = "ATT&CK website"
- version = "4.0.4"
+ version = "4.0.5"
filename = "CHANGELOG.md"
issue_format = "[#{issue}](https://github.com/mitre-attack/attack-website/issues/{issue})"
template = ".towncrier.template.md"
diff --git a/requirements.txt b/requirements.txt
index 5112a54e0c4..065c5a9d9b6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-GitPython==3.1.31
+GitPython==3.1.32
Markdown==3.4.3
bleach==6.0.0
colorama==0.4.6
|