feat(ttp): fetch + verify MITRE ATT&CK LICENSE alongside the bundle
MITRE's ATT&CK Terms of Use require reproducing their copyright + license alongside any cached copy of ATT&CK data. Today we ship the bundle but not the license — this commit closes that compliance gap. - attack_version.py pins ATTACK_LICENSE_URL + ATTACK_LICENSE_SHA256 + ATTACK_LICENSE_FILENAME, sourced from the same attack-stix-data repo as the bundle. - attack_stix.py:_fetch_license downloads LICENSE.txt next to the bundle. License sha mismatch is logged + refreshed (license text gets occasional formatting tweaks; not a security event), unlike the bundle which stays fail-closed. - _ensure_license is the compliance ratchet: resolve_bundle_path refuses to return without LICENSE.txt on disk. Override-mode (DECNET_ATTACK_BUNDLE) checks for a sibling LICENSE.txt first, then DECNET_ATTACK_LICENSE, then the cache dir. - python -m decnet.ttp.attack_stix license prints the cached license to stdout for operator audit. - loaded_license_path() exposes the active license path read-only. - tests/ttp/test_attack_license.py covers happy paths (sibling + explicit env), refusal when DECNET_ATTACK_LICENSE points at a missing file, the CLI subcommand, and the pinned-sha shape.
This commit is contained in:
@@ -29,8 +29,30 @@ ATTACK_BUNDLE_URL: Final[str] = (
|
||||
f"/master/enterprise-attack/enterprise-attack-{ATTACK_BUNDLE_VERSION}.json"
|
||||
)
|
||||
|
||||
# MITRE's ATT&CK Terms of Use (https://attack.mitre.org/resources/legal-and-branding/terms-of-use/)
|
||||
# require reproducing their copyright + license alongside any cached
|
||||
# copy of ATT&CK data. The license file lives at the root of the
|
||||
# attack-stix-data repository and is fetched into the same cache dir
|
||||
# as the bundle. ``resolve_bundle_path`` refuses to operate without
|
||||
# this file present — a hard compliance ratchet, not a soft warning.
|
||||
ATTACK_LICENSE_URL: Final[str] = (
|
||||
"https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/LICENSE.txt"
|
||||
)
|
||||
|
||||
# sha256 of the LICENSE.txt at the time of pinning. License text gets
|
||||
# occasional formatting touch-ups, so a mismatch is logged + refreshed
|
||||
# rather than fail-closed (see _fetch_license in attack_stix.py).
|
||||
ATTACK_LICENSE_SHA256: Final[str] = (
|
||||
"738144f7fb054722a4ef9d3367c51710341dc12fc574c6ac3a41daaaecd8bf5e"
|
||||
)
|
||||
|
||||
ATTACK_LICENSE_FILENAME: Final[str] = "LICENSE.txt"
|
||||
|
||||
__all__ = [
|
||||
"ATTACK_BUNDLE_SHA256",
|
||||
"ATTACK_BUNDLE_URL",
|
||||
"ATTACK_BUNDLE_VERSION",
|
||||
"ATTACK_LICENSE_FILENAME",
|
||||
"ATTACK_LICENSE_SHA256",
|
||||
"ATTACK_LICENSE_URL",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user