diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000..f07a5f25 --- /dev/null +++ b/conftest.py @@ -0,0 +1,36 @@ +"""Pytest command-line options for mitreattack-python.""" + + +def pytest_addoption(parser): + """Register pytest options for selecting ATT&CK STIX test data.""" + parser.addoption( + "--stix-enterprise", + action="store", + default=None, + help="Path to an Enterprise ATT&CK STIX bundle to use in tests.", + ) + parser.addoption( + "--stix-mobile", + action="store", + default=None, + help="Path to a Mobile ATT&CK STIX bundle to use in tests.", + ) + parser.addoption( + "--stix-ics", + action="store", + default=None, + help="Path to an ICS ATT&CK STIX bundle to use in tests.", + ) + parser.addoption( + "--attack-version", + action="store", + default=None, + help="ATT&CK release version to download and use for STIX-backed tests.", + ) + parser.addoption( + "--stix-version", + action="store", + choices=("2.0", "2.1"), + default="2.0", + help="STIX version to download when --attack-version is used. Defaults to 2.0.", + ) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 39073744..fda140fd 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -56,6 +56,21 @@ just test-cov # Run tests with coverage report just build # Build the package ``` +To run STIX-backed tests against specific local bundles, pass the bundle paths to pytest: + +```bash +uv run pytest \ + --stix-enterprise /path/to/enterprise-attack.json \ + --stix-mobile /path/to/mobile-attack.json \ + --stix-ics /path/to/ics-attack.json +``` + +To have pytest download a specific ATT&CK release instead, use: + +```bash +uv run pytest --attack-version 16.1 --stix-version 2.1 +``` + ### Pull Requests When making a pull request, please make sure to: diff --git a/examples/generate_multiple_attack_diffs.py b/examples/generate_multiple_attack_diffs.py index c3037d8d..7459f807 100644 --- a/examples/generate_multiple_attack_diffs.py +++ b/examples/generate_multiple_attack_diffs.py @@ -1,36 +1,75 @@ +"""Generate ATT&CK changelog outputs for multiple release pairs.""" + +import argparse + from mitreattack.diffStix.changelog_helper import get_new_changelog_md +DOMAINS = ["enterprise-attack", "mobile-attack", "ics-attack"] +VERSION_PAIRS = [ + ("17.1", "18.0"), + ("18.0", "18.1"), +] + + +def get_release_output_folder(old_version: str, new_version: str) -> str: + """Return the output folder for a release comparison.""" + return f"output/v{old_version}-v{new_version}" + + +def get_artifact_link_prefix(old_version: str, new_version: str, *, attack_website_links: bool = False) -> str: + """Return the link prefix for generated layers and changelog JSON.""" + if not attack_website_links: + return "" + return f"/docs/changelogs/v{old_version}-v{new_version}" + + +def get_parsed_args(): + """Parse command line arguments for the example script.""" + parser = argparse.ArgumentParser(description="Generate ATT&CK changelog outputs for multiple release pairs.") + parser.add_argument( + "-w", + "--attack-website-links", + action="store_true", + help="Use ATT&CK website paths for links to generated layers and changelog JSON.", + ) + return parser.parse_args() + + +def generate_diff(old_version: str, new_version: str, *, attack_website_links: bool = False): + """Generate changelog outputs for a single ATT&CK release pair.""" + output_folder = get_release_output_folder(old_version, new_version) + print(f"Generating ATT&CK Diffs between {old_version}-{new_version}: {output_folder}") + + get_new_changelog_md( + domains=DOMAINS, + layers=[ + f"{output_folder}/layer-enterprise.json", + f"{output_folder}/layer-mobile.json", + f"{output_folder}/layer-ics.json", + ], + old=f"attack-releases/stix-2.0/v{old_version}", + new=f"attack-releases/stix-2.0/v{new_version}", + show_key=True, + # site_prefix: str = "", + verbose=True, + include_contributors=True, + markdown_file=f"{output_folder}/changelog.md", + html_file=f"{output_folder}/index.html", + html_file_detailed=f"{output_folder}/changelog-detailed.html", + additional_formats_prefix=get_artifact_link_prefix( + old_version, + new_version, + attack_website_links=attack_website_links, + ), + json_file=f"{output_folder}/changelog.json", + ) + def main(): - version_pairs = [ - ("17.1", "18.0"), - ("18.0", "18.1"), - ] - for version_pair in version_pairs: - old_version = version_pair[0] - new_version = version_pair[1] - - output_folder = f"output/v{old_version}-v{new_version}" - print(f"Generating ATT&CK Diffs between {old_version}-{new_version}: {output_folder}") - - get_new_changelog_md( - domains=["enterprise-attack", "mobile-attack", "ics-attack"], - layers=[ - f"{output_folder}/layer-enterprise.json", - f"{output_folder}/layer-mobile.json", - f"{output_folder}/layer-ics.json", - ], - old=f"attack-releases/stix-2.0/v{old_version}", - new=f"attack-releases/stix-2.0/v{new_version}", - show_key=True, - # site_prefix: str = "", - verbose=True, - include_contributors=True, - markdown_file=f"{output_folder}/changelog.md", - html_file=f"{output_folder}/index.html", - html_file_detailed=f"{output_folder}/changelog-detailed.html", - json_file=f"{output_folder}/changelog.json", - ) + """Generate changelog outputs for all configured ATT&CK release pairs.""" + args = get_parsed_args() + for old_version, new_version in VERSION_PAIRS: + generate_diff(old_version, new_version, attack_website_links=args.attack_website_links) if __name__ == "__main__": diff --git a/mitreattack/diffStix/README.md b/mitreattack/diffStix/README.md index 292fb4a6..a1824332 100644 --- a/mitreattack/diffStix/README.md +++ b/mitreattack/diffStix/README.md @@ -14,7 +14,7 @@ Print full usage instructions: # You must run `pip install mitreattack-python` in order to access the diff_stix command diff_stix --help usage: diff_stix [-h] [--old OLD] [--new NEW] [--domains {enterprise-attack,mobile-attack,ics-attack} [{enterprise-attack,mobile-attack,ics-attack} ...]] [--markdown-file MARKDOWN_FILE] [--html-file HTML_FILE] [--html-file-detailed HTML_FILE_DETAILED] - [--json-file JSON_FILE] [--layers [LAYERS ...]] [--site_prefix SITE_PREFIX] [--unchanged] [--use-mitre-cti] [--show-key] [--contributors] [--no-contributors] [-v] + [--json-file JSON_FILE] [--layers [LAYERS ...]] [--site_prefix SITE_PREFIX] [--additional-formats-prefix ADDITIONAL_FORMATS_PREFIX] [--unchanged] [--use-mitre-cti] [--show-key] [--contributors] [--no-contributors] [-v] Create changelog reports on the differences between two versions of the ATT&CK content. Takes STIX bundles as input. For default operation, put enterprise-attack.json, mobile-attack.json, and ics-attack.json bundles in 'old' and 'new' folders for the script to compare. @@ -37,6 +37,8 @@ options: output/January_2023_Updates_Mobile.json, output/January_2023_Updates_ICS.json, output/January_2023_Updates_Pre.json --site_prefix SITE_PREFIX Prefix links in markdown output, e.g. [prefix]/techniques/T1484 + --additional-formats-prefix ADDITIONAL_FORMATS_PREFIX + Prefix detailed HTML links to generated layers and changelog JSON. --unchanged Show objects without changes in the markdown output --use-mitre-cti Use content from the MITRE CTI repo for the -old data --show-key Add a key explaining the change types to the markdown diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 5428f260..99cd0404 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -1871,7 +1871,14 @@ def layers_dict_to_files(outfiles, layers): json.dump(layers["ics-attack"], open(ics_attack_layer_file, "w"), indent=4) -def write_detailed_html(html_file_detailed: str, diffStix: DiffStix): +def _get_additional_format_href(filename: str, additional_formats_prefix: str = "") -> str: + """Return a link to an additional changelog output file.""" + if not additional_formats_prefix: + return filename + return f"{additional_formats_prefix.rstrip('/')}/{filename}" + + +def write_detailed_html(html_file_detailed: str, diffStix: DiffStix, additional_formats_prefix: str = ""): """Write a detailed HTML report of changes between ATT&CK versions. Parameters @@ -1880,6 +1887,8 @@ def write_detailed_html(html_file_detailed: str, diffStix: DiffStix): File to write HTML for the detailed changelog. diffStix : DiffStix An instance of a DiffStix object. + additional_formats_prefix : str, optional + Prefix for links to generated layer and JSON files, by default "". """ old_version = diffStix.data["old"]["enterprise-attack"]["attack_release_version"] new_version = diffStix.data["new"]["enterprise-attack"]["attack_release_version"] @@ -1889,6 +1898,11 @@ def write_detailed_html(html_file_detailed: str, diffStix: DiffStix): else: header = f"
@@ -1929,11 +1943,11 @@ def write_detailed_html(html_file_detailed: str, diffStix: DiffStix):
Additional formatsThese ATT&CK Navigator layer files can be uploaded to ATT&CK Navigator manually.
This JSON file contains the machine readble output used to create this page: changelog.json +This JSON file contains the machine readble output used to create this page: changelog.json """ ), ] @@ -2256,6 +2270,13 @@ def get_parsed_args(): help="Prefix links in markdown output, e.g. [prefix]/techniques/T1484", ) + parser.add_argument( + "--additional-formats-prefix", + type=str, + default="", + help="Prefix detailed HTML links to generated layers and changelog JSON.", + ) + parser.add_argument( "--unchanged", action="store_true", @@ -2331,6 +2352,7 @@ def get_new_changelog_md( markdown_file: Optional[str] = None, html_file: Optional[str] = None, html_file_detailed: Optional[str] = None, + additional_formats_prefix: str = "", json_file: Optional[str] = None, ) -> str: """Get a Markdown string representation of differences between two ATT&CK versions. @@ -2365,6 +2387,8 @@ def get_new_changelog_md( If set, writes an HTML file from the parsed markdown, by default None html_file_detailed : str, optional If set, writes a more detailed HTML page, by default None + additional_formats_prefix : str, optional + Prefix for detailed HTML links to generated layer and JSON files, by default "". json_file : str, optional If set, writes JSON file of the changes, by default None @@ -2414,7 +2438,11 @@ def get_new_changelog_md( if html_file_detailed: Path(html_file_detailed).parent.mkdir(parents=True, exist_ok=True) logger.info("Writing detailed updates to file") - write_detailed_html(html_file_detailed=html_file_detailed, diffStix=diffStix) + write_detailed_html( + html_file_detailed=html_file_detailed, + diffStix=diffStix, + additional_formats_prefix=additional_formats_prefix, + ) if layers: if len(layers) == 0: @@ -2457,6 +2485,7 @@ def main(): markdown_file=args.markdown_file, html_file=args.html_file, html_file_detailed=args.html_file_detailed, + additional_formats_prefix=args.additional_formats_prefix, json_file=args.json_file, ) diff --git a/mitreattack/release_info.py b/mitreattack/release_info.py index 661d7b63..f3f40f50 100644 --- a/mitreattack/release_info.py +++ b/mitreattack/release_info.py @@ -8,7 +8,7 @@ # This file contains SHA256 hashes for officially released ATT&CK versions # download_string = f"https://raw.githubusercontent.com/mitre/cti/ATT%26CK-v{release}/{domain}-attack/{domain}-attack.json" -LATEST_VERSION = "18.1" +LATEST_VERSION = "19.0" STIX20 = { "enterprise": { @@ -48,6 +48,7 @@ "17.1": "9537a22166367a5b3c1434f5b17b27361cb9c88b34926e655344768fdbda3e85", "18.0": "6ecc9655954a4a0eeada8ba6f18f1d053fbcacce0e5411f677729d1dafce5673", "18.1": "628c4fc3c01b9ef37e1cd84ca3c421e1d43950a43464a14aabd1a7089601dc45", + "19.0": "987d0cfddb1e65797457cf2b045df9161140ede71fd627f15dfdd73c2a2c72ab", }, "mobile": { "3.0": "1385d94348054c1c1f7cdc652f0719db353b60c923949b10cbf8a2e815a86eb3", @@ -89,6 +90,7 @@ "17.1": "736078773f05ee943c0aa71bf71b935b04315c134809e8b678bd45c89cb1ab49", "18.0": "18ab338f8663200bdc62b982d5821ec255d9b420947b68e6d024000a44620404", "18.1": "62ecc7e3cabacc2430de0d65078a3726b6d8f7b0eff9493fd6403b514f66518d", + "19.0": "1f3f050d6d4cb0a75a07a0c0dd0834ce2de176a0096a3ddd7ffc2ee2feeff592", }, "ics": { "8.0": "2e9e9d0d9f0e5d14f64cf2788f46a1a4403bc88ab6ddd419cfcdfe617b0c920d", @@ -115,6 +117,7 @@ "17.1": "f0bd44fa2e167f2e9e94700f9081571dfedc49bebd856ea0d7ec24cf896d298b", "18.0": "e19597196d96ef07e7d1b0dc3a1e67f792a27f61d615a3242c694169fe81011c", "18.1": "76655cd7c363ca9a7474a95e9d60522a0c3211eaf2efad5b5e9cd7f9e0365b51", + "19.0": "17f519e62fa85aded4ef6035dff348dd790dd177672757ceaded8e85f8caa950", }, "pre": { "3.0": "bc59c1b1398a133cf0adb98e4e28396fdb6a5a2e2353cecb1783c425f066fc94", @@ -172,6 +175,7 @@ "17.1": "0d1c347a4d584cf7e11ef46556c33b7689341443bf86299188d46c307274323b", "18.0": "ff94838b09edfe7d59eec1cd7af0a1e229c4bc0ae0bdfa98ad170aeec9c3e272", "18.1": "f857d8f78f2f0c0b7db321a711a39fba98546c1e3076a657684850c83d0962fb", + "19.0": "df520ea0775a57db7bff760145b02fed89290802913e056b7ed5970b02f3626a", }, "mobile": { "1.0": "7da1903596bb69ef75a3c2a6c79e80328657bfed9226b2ed400ca18c88e0c1ea", @@ -212,6 +216,7 @@ "17.1": "33968697b94a5ff5568016a28bbcc93f7869dc2f2b2653ead833758867ab5bc9", "18.0": "f5f7f21c8daa59cc83f94432f0d77743be14d717f61f0464465b663508ef6d4f", "18.1": "c6dd56996586b2d1484e6555f9f5307f379dff24e7632e6af23097ef25656ea9", + "19.0": "e6c65d1c5b22ad9eb52811c9a0b66f31537d4a4ea71f40da9dfee96412a42315", }, "ics": { "8.0": "f3b53ff8d7f0f21f3e48c651edf68353aeb3e07727c32c3e47ef882e3bca10ab", @@ -238,6 +243,7 @@ "17.1": "cb207f963ca270994d9dabefe52237d46cf25056f154057f4b961f1c0803a8f3", "18.0": "e0c64def90415d548131009ba2ba4d8a4a725ca2293861a4cc2f9e8712625531", "18.1": "a7c0106492843485340710be9e841c1584d8fc6da8950e7097db0e7b5bc9f164", + "19.0": "4a986f4a440aa0c36bd352e9b320de82160c456a680f7700fe4585d90b4a2522", }, } diff --git a/pyproject.toml b/pyproject.toml index 5de140e0..2dd0b877 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,6 +79,9 @@ package = true module-name = "mitreattack" module-root = "" +[tool.pytest.ini_options] +testpaths = ["tests"] + [tool.ruff] line-length = 120 extend-exclude = ["tests/resources/", "examples/", "__init__.py"] diff --git a/tests/changelog/cli/test_argument_handling.py b/tests/changelog/cli/test_argument_handling.py index 6178cf65..70816e79 100644 --- a/tests/changelog/cli/test_argument_handling.py +++ b/tests/changelog/cli/test_argument_handling.py @@ -38,6 +38,7 @@ def _assert_default_args(self, args): assert args.verbose is False assert args.use_mitre_cti is False assert args.site_prefix == "" + assert args.additional_formats_prefix == "" def test_get_parsed_args_default_values(self, monkeypatch): """Test default argument values.""" @@ -68,6 +69,8 @@ def test_get_parsed_args_all_options(self, monkeypatch): "layer3.json", "--site_prefix", "https://example.com", + "--additional-formats-prefix", + "/docs/changelogs/v16.1-v17.0", "--unchanged", "--show-key", "--no-contributors", @@ -85,6 +88,7 @@ def test_get_parsed_args_all_options(self, monkeypatch): assert args.json_file == "test.json" assert args.layers == ["layer1.json", "layer2.json", "layer3.json"] assert args.site_prefix == "https://example.com" + assert args.additional_formats_prefix == "/docs/changelogs/v16.1-v17.0" assert args.unchanged is True assert args.show_key is True assert args.contributors is False @@ -182,6 +186,8 @@ def test_get_parsed_args_boolean_flags(self, flag, expected_attr, expected_value ("--site_prefix", "https://custom.com", "site_prefix"), ("--site_prefix", "", "site_prefix"), # Empty site prefix ("--site_prefix", "https://example.com/", "site_prefix"), # With trailing slash + ("--additional-formats-prefix", "/docs/changelogs/v16.1-v17.0", "additional_formats_prefix"), + ("--additional-formats-prefix", "", "additional_formats_prefix"), ], ) def test_get_parsed_args_string_options(self, option, value, expected_attr, monkeypatch): diff --git a/tests/changelog/formatting/test_html_output.py b/tests/changelog/formatting/test_html_output.py index 6877f71c..f90b1cca 100644 --- a/tests/changelog/formatting/test_html_output.py +++ b/tests/changelog/formatting/test_html_output.py @@ -78,6 +78,40 @@ def test_write_detailed_html_basic( assert f"ATT&CK Changes Between v{old_version} and v{new_version}" in html_content assert "Techniques" in html_content or "" in html_content # Should have some header structure + def test_write_detailed_html_additional_format_links_default_to_relative(self, tmp_path, lightweight_diffstix): + """Test detailed HTML links to generated artifacts with relative paths by default.""" + html_file = tmp_path / "detailed.html" + lightweight_diffstix.data["old"]["enterprise-attack"]["attack_release_version"] = "16.1" + lightweight_diffstix.data["new"]["enterprise-attack"]["attack_release_version"] = "17.0" + + write_detailed_html(str(html_file), lightweight_diffstix) + + html_content = html_file.read_text(encoding="utf-8") + assert 'Enterprise changes' in html_content + assert 'Mobile changes' in html_content + assert 'ICS changes' in html_content + assert 'changelog.json' in html_content + + def test_write_detailed_html_additional_format_links_use_additional_formats_prefix( + self, tmp_path, lightweight_diffstix + ): + """Test detailed HTML links to generated artifacts can be prefixed for website releases.""" + html_file = tmp_path / "detailed.html" + lightweight_diffstix.data["old"]["enterprise-attack"]["attack_release_version"] = "16.1" + lightweight_diffstix.data["new"]["enterprise-attack"]["attack_release_version"] = "17.0" + + write_detailed_html( + str(html_file), + lightweight_diffstix, + additional_formats_prefix="/docs/changelogs/v16.1-v17.0/", + ) + + html_content = html_file.read_text(encoding="utf-8") + assert 'Enterprise changes' in html_content + assert 'Mobile changes' in html_content + assert 'ICS changes' in html_content + assert 'changelog.json' in html_content + def test_html_document_structure(self): """Test basic HTML document structure.""" title = "ATT&CK Changes" diff --git a/tests/conftest.py b/tests/conftest.py index 115ff82e..5e58f6c8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,9 +13,47 @@ from .resources.testing_data import example_layer_v3_all, example_layer_v43_dict -STIX_LOCATION_ENTERPRISE = os.getenv("STIX_LOCATION_ENTERPRISE") -STIX_LOCATION_MOBILE = os.getenv("STIX_LOCATION_MOBILE") -STIX_LOCATION_ICS = os.getenv("STIX_LOCATION_ICS") +STIX_LOCATION_ENV_VARS = { + "enterprise": "STIX_LOCATION_ENTERPRISE", + "mobile": "STIX_LOCATION_MOBILE", + "ics": "STIX_LOCATION_ICS", +} +STIX_LOCATION_OPTIONS = { + "enterprise": "stix_enterprise", + "mobile": "stix_mobile", + "ics": "stix_ics", +} + + +def _get_config_option(config, name): + """Return a pytest option value, including when the option is unavailable in test doubles.""" + return config.getoption(name, default=None) + + +def _get_requested_stix_file(request, domain): + """Get a configured STIX file path for a domain from CLI options or environment.""" + cli_value = _get_config_option(request.config, STIX_LOCATION_OPTIONS[domain]) + if cli_value: + return cli_value + + return os.getenv(STIX_LOCATION_ENV_VARS[domain]) + + +def _all_stix_files_requested(request): + """Return whether every domain has a configured local STIX file.""" + return all(_get_requested_stix_file(request, domain) for domain in STIX_LOCATION_OPTIONS) + + +def _get_requested_attack_stix_param(request): + """Build the attack_stix_dir fixture parameter from pytest version options.""" + attack_version = _get_config_option(request.config, "attack_version") + if not attack_version: + return None + + return { + "attack_version": attack_version, + "stix_version": _get_config_option(request.config, "stix_version") or "2.0", + } def _parse_version_param(versions_param): @@ -150,17 +188,20 @@ def attack_stix_dir(request, tmp_path_factory): dict Directory paths for requested ATT&CK versions """ - versions_param = getattr(request, "param", None) + if _all_stix_files_requested(request): + yield {} + return + + versions_param = getattr(request, "param", None) or _get_requested_attack_stix_param(request) result_paths = _download_attack_stix_data(versions_param, tmp_path_factory) yield result_paths @pytest.fixture(scope="session") -def stix_file_enterprise_latest(attack_stix_dir): +def stix_file_enterprise_latest(request, attack_stix_dir): """Get path to Enterprise ATT&CK STIX file. - Uses environment variable STIX_LOCATION_ENTERPRISE if set, - otherwise constructs path from attack_stix_dir. + Uses --stix-enterprise or STIX_LOCATION_ENTERPRISE if set, otherwise constructs path from attack_stix_dir. Parameters ---------- @@ -172,18 +213,18 @@ def stix_file_enterprise_latest(attack_stix_dir): str Path to Enterprise ATT&CK STIX file """ - if STIX_LOCATION_ENTERPRISE: - return STIX_LOCATION_ENTERPRISE + requested_stix_file = _get_requested_stix_file(request, "enterprise") + if requested_stix_file: + return requested_stix_file return _get_stix_file_path(attack_stix_dir, "enterprise") @pytest.fixture(scope="session") -def stix_file_mobile_latest(attack_stix_dir): +def stix_file_mobile_latest(request, attack_stix_dir): """Get path to Mobile ATT&CK STIX file. - Uses environment variable STIX_LOCATION_MOBILE if set, - otherwise constructs path from attack_stix_dir. + Uses --stix-mobile or STIX_LOCATION_MOBILE if set, otherwise constructs path from attack_stix_dir. Parameters ---------- @@ -195,18 +236,18 @@ def stix_file_mobile_latest(attack_stix_dir): str Path to Mobile ATT&CK STIX file """ - if STIX_LOCATION_MOBILE: - return STIX_LOCATION_MOBILE + requested_stix_file = _get_requested_stix_file(request, "mobile") + if requested_stix_file: + return requested_stix_file return _get_stix_file_path(attack_stix_dir, "mobile") @pytest.fixture(scope="session") -def stix_file_ics_latest(attack_stix_dir): +def stix_file_ics_latest(request, attack_stix_dir): """Get path to ICS ATT&CK STIX file. - Uses environment variable STIX_LOCATION_ICS if set, - otherwise constructs path from attack_stix_dir. + Uses --stix-ics or STIX_LOCATION_ICS if set, otherwise constructs path from attack_stix_dir. Parameters ---------- @@ -218,8 +259,9 @@ def stix_file_ics_latest(attack_stix_dir): str Path to ICS ATT&CK STIX file """ - if STIX_LOCATION_ICS: - return STIX_LOCATION_ICS + requested_stix_file = _get_requested_stix_file(request, "ics") + if requested_stix_file: + return requested_stix_file return _get_stix_file_path(attack_stix_dir, "ics") diff --git a/tests/test_mitreattackdata.py b/tests/test_mitreattackdata.py index 0fbbec89..8d6b9696 100644 --- a/tests/test_mitreattackdata.py +++ b/tests/test_mitreattackdata.py @@ -97,7 +97,7 @@ def test_techniques_by_platform(self, mitre_attack_data_enterprise: MitreAttackD def test_techniques_by_tactic(self, mitre_attack_data_enterprise: MitreAttackData): """Test that techniques can be retrieved by tactic.""" # TODO: use all tactic shortnames - tactic_shortnames = ["defense-evasion", "impact"] + tactic_shortnames = ["collection", "impact"] for tactic_shortname in tactic_shortnames: techniques = mitre_attack_data_enterprise.get_techniques_by_tactic( tactic_shortname=tactic_shortname, domain="enterprise-attack" |