diff --git a/CHANGELOG.md b/CHANGELOG.md index e84c7c5..579be10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ *** +# Version 1.8.1 - December 2024 + +- Added support for overriding multiple version of the same Variant via the Blueprint + +*** + # Version 1.8.0 - December 2024 - Added support for Blueprint overrides to Darkpool diff --git a/dist/marketmaker-1.8.0-py3-none-any.whl b/dist/marketmaker-1.8.1-py3-none-any.whl similarity index 99% rename from dist/marketmaker-1.8.0-py3-none-any.whl rename to dist/marketmaker-1.8.1-py3-none-any.whl index 7009248..bc926ba 100644 Binary files a/dist/marketmaker-1.8.0-py3-none-any.whl and b/dist/marketmaker-1.8.1-py3-none-any.whl differ diff --git a/docs/Blueprints.md b/docs/Blueprints.md index 74beb2c..1acf12e 100644 --- a/docs/Blueprints.md +++ b/docs/Blueprints.md @@ -84,6 +84,20 @@ campaigns: In most cases, users should stick with the first form. +You can also specify these Variant structures as a list. +This is intended to support instances where you need to include multiple version of the same Variant and override one or both versions. Example: + +``` +campaigns: + Command and Control: + T1071.004: + dnsc2: + - version: 1 + name: "Override version 1" + - version: 2 + name: "Override version 2" +``` + ### Groups Groups are used to add additional threat group metadata to exported test cases and follow the structure: diff --git a/libmm/sql.py b/libmm/sql.py index 8d7b595..8f6ee9e 100644 --- a/libmm/sql.py +++ b/libmm/sql.py @@ -377,53 +377,65 @@ def from_yaml(cls, y: dict): # - integer -> ex: 1 # - string -> ex: 1;2 # - dict -> ex: { ... } + # - list -> ex: [ ... ] # # the string form allows for multiple version of the same variant # this has to be done like this to avoid duplicate keys in YAML # # the dict form is a blueprint-level override that lets the # blueprint override certain fields in a variant + # + # the list form allows for overriding multiple versions of the same variant - do_override = False - if type(variant_block) in [str, int]: - versions = str(variant_block) - if ";" in versions: - versions = [version.strip() for version in versions.split(";")] - else: - versions = [versions] + if isinstance(variant_block, list): + variant_list = variant_block else: - do_override = True - versions = [variant_block.get("version")] - - for version in versions: - try: - variant = lookup_variant(tid=tid, name=variant_name, version=version) - except Exception as e: - logger.error(e) - continue - - session.add(variant) - session.add(campaign) - campaign.variants.append(variant) - - if do_override: - override = VariantOverride( - referencces=variant_block.get("references", None), - guidance=variant_block.get("guidance", None), - display_name=variant_block.get("name", None), - variant=variant, - blueprint_id=blueprint.id, - campaign_id=campaign.id, + variant_list = [variant_block] + + for variant_list_item in variant_list: + do_override = False + if isinstance(variant_list_item, (str, int)): + version_str = str(variant_list_item) + else: + do_override = True + version_str = str(variant_list_item.get("version")) + + if ";" in version_str: + versions = [version.strip() for version in version_str.split(";")] + else: + versions = [version_str] + + for version in versions: + try: + variant = lookup_variant(tid=tid, name=variant_name, version=version) + except Exception as e: + logger.error(e) + continue + + session.add(variant) + session.add(campaign) + campaign.variants.append(variant) + + if do_override: + new_name = variant_list_item.get("name", None) + + override = VariantOverride( + referencces=variant_list_item.get("references", None), + guidance=variant_list_item.get("guidance", None), + display_name=new_name if new_name else variant.display_name, + variant=variant, + blueprint_id=blueprint.id, + campaign_id=campaign.id, + ) + session.add(override) + + # handle blueprint-level groups based on matching tid+blueprint + group_matches = ( + session.query(BlueprintGroup) + .filter(BlueprintGroup.tid == tid, BlueprintGroup.blueprint_id == blueprint.id) + .all() ) - session.add(override) - - # handle blueprint-level groups based on matching tid+blueprint - group_matches = ( - session.query(BlueprintGroup) - .filter(BlueprintGroup.tid == tid, BlueprintGroup.blueprint_id == blueprint.id) - .all() - ) - variant.groups.extend(group_matches) + variant.groups.extend(group_matches) session.commit() blueprint.emit_loaded() diff --git a/pyproject.toml b/pyproject.toml index 5393d45..55f22e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "marketmaker" -version = "1.8.0" +version = "1.8.1" description = "Suite of tools for managing and creating attack plans" authors = ["2XXE "] readme = "README.md"