fix(1.2): relocate ATT&CK bundle to decnet/data/, bump 19.0 -> 19.1

Bundle pointer moved from repo root to decnet/data/ (with LICENSE.txt),
gitignored + fetched on demand (51MB, MITRE-licensed). Version pin bumped
19.0->19.1 with the new sha256; license unchanged. All _REPO_BUNDLE test
constants repointed. Fixes test-web failures after the repo-root bundle
was deleted.
This commit is contained in:
2026-06-18 19:02:58 -04:00
parent a5e11f7d86
commit 1a765854ec
14 changed files with 28 additions and 15 deletions

View File

@@ -19,6 +19,12 @@ workers the in-process supervisor can't co-host.
`gc.freeze()` unnecessary thanks to PEP 683 immortal objects). Not yet wired to `gc.freeze()` unnecessary thanks to PEP 683 immortal objects). Not yet wired to
a command — the target worker set lands next. a command — the target worker set lands next.
### Changed
- MITRE ATT&CK Enterprise bundle pinned 19.0 → **19.1**. The bundle and its
LICENSE now resolve from `decnet/data/` (hash-pinned in `attack_version.py`,
fetched on demand via `python -m decnet.ttp.attack_stix fetch`, gitignored —
not committed).
## [1.1.1] - 2026-06-18 ## [1.1.1] - 2026-06-18
### Fixed ### Fixed

7
decnet/data/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
# MITRE ATT&CK STIX bundle + license live here but are NOT committed:
# ~51MB and MITRE-licensed (fetched on demand, hash-pinned in attack_version.py).
#
# Populate locally / in CI with:
# DECNET_ATTACK_CACHE_DIR=decnet/data python -m decnet.ttp.attack_stix fetch
/enterprise-attack-*.json
/LICENSE.txt

View File

@@ -16,12 +16,12 @@ from __future__ import annotations
from typing import Final from typing import Final
ATTACK_BUNDLE_VERSION: Final[str] = "19.0" ATTACK_BUNDLE_VERSION: Final[str] = "19.1"
# sha256 of the canonical MITRE-published enterprise-attack-19.0.json # sha256 of the canonical MITRE-published enterprise-attack-19.1.json
# from https://github.com/mitre-attack/attack-stix-data. # from https://github.com/mitre-attack/attack-stix-data.
ATTACK_BUNDLE_SHA256: Final[str] = ( ATTACK_BUNDLE_SHA256: Final[str] = (
"df520ea0775a57db7bff760145b02fed89290802913e056b7ed5970b02f3626a" "bdf1ce86a4e604214c5076d37ae4dcb322678afc528df8492e6fdc1b554f5da3"
) )
# Raw download URL for the pinned version. # Raw download URL for the pinned version.

View File

@@ -20,7 +20,7 @@ from decnet.clustering import ukc
from decnet.ttp import attack_stix from decnet.ttp import attack_stix
from decnet.ttp.impl import intel_lifter from decnet.ttp.impl import intel_lifter
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -19,7 +19,7 @@ from decnet.ttp import attack_stix
from decnet.ttp.attack_catalog import technique_name from decnet.ttp.attack_catalog import technique_name
_RULES_DIR = Path(__file__).resolve().parents[2] / "rules" / "ttp" _RULES_DIR = Path(__file__).resolve().parents[2] / "rules" / "ttp"
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(scope="module", autouse=True) @pytest.fixture(scope="module", autouse=True)

View File

@@ -19,7 +19,7 @@ from decnet.ttp.attack_version import (
ATTACK_LICENSE_SHA256, ATTACK_LICENSE_SHA256,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -15,7 +15,7 @@ import pytest
from decnet.ttp import attack_stix from decnet.ttp import attack_stix
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -24,7 +24,7 @@ from decnet.ttp.impl._emit import emit_tags
from decnet.ttp.impl.rule_engine import CompiledRule from decnet.ttp.impl.rule_engine import CompiledRule
from decnet.ttp.store.base import RuleState from decnet.ttp.store.base import RuleState
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -19,7 +19,7 @@ from decnet.web.router.ttp.api_get_groups_for_technique import (
api_groups_for_technique, api_groups_for_technique,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -31,7 +31,7 @@ from decnet.ttp.data.intel_loader import (
load_provider_mapping, load_provider_mapping,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
_DATA_DIR = Path(__file__).resolve().parents[2] / "decnet" / "ttp" / "data" / "intel" _DATA_DIR = Path(__file__).resolve().parents[2] / "decnet" / "ttp" / "data" / "intel"

View File

@@ -14,7 +14,7 @@ from decnet.web.router.attackers.api_export_attacker_misp import (
api_export_attacker_misp, api_export_attacker_misp,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
_FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"} _FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"}

View File

@@ -2,7 +2,7 @@
"""Tests for GET /api/v1/attackers/{uuid}/export/stix. """Tests for GET /api/v1/attackers/{uuid}/export/stix.
Tests call the handler directly (no TestClient). The attack_stix bundle Tests call the handler directly (no TestClient). The attack_stix bundle
is pinned to the repo's enterprise-attack-19.0.json so Sighting and is pinned to the repo's decnet/data/enterprise-attack-19.1.json so Sighting and
Relationship target_refs are real MITRE STIX IDs. Relationship target_refs are real MITRE STIX IDs.
""" """
from __future__ import annotations from __future__ import annotations
@@ -20,7 +20,7 @@ from decnet.web.router.attackers.api_export_attacker_stix import (
api_export_attacker_stix, api_export_attacker_stix,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
_FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"} _FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"}

View File

@@ -14,7 +14,7 @@ from decnet.web.router.attackers.api_export_attackers_misp import (
api_export_attackers_misp, api_export_attackers_misp,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
_FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"} _FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"}

View File

@@ -15,7 +15,7 @@ from decnet.web.router.attackers.api_export_attackers_stix import (
api_export_attackers_stix, api_export_attackers_stix,
) )
_REPO_BUNDLE = Path(__file__).resolve().parents[2] / "enterprise-attack-19.0.json" _REPO_BUNDLE = Path(__file__).resolve().parents[2] / "decnet" / "data" / "enterprise-attack-19.1.json"
_FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"} _FAKE_USER: dict = {"uuid": "test-user", "role": "viewer"}