detkit-cli 0.1.5__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/PKG-INFO +21 -4
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/README.md +20 -3
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/cli.py +22 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/docs.py +48 -0
- detkit_cli-0.1.6/detkit-navigator.json +50 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/PKG-INFO +21 -4
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/SOURCES.txt +1 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/scm_file_list.json +1 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/scm_version.json +2 -2
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/tests/test_docs.py +20 -1
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.github/workflows/ci.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.github/workflows/publish.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.gitignore +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/.pre-commit-hooks.yaml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/CONTRIBUTING.md +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/LICENSE +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/action.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/__init__.py +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/__main__.py +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/attack_enterprise.json +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit/evaluator.py +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit-demo.gif +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit-demo.tape +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/dependency_links.txt +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/entry_points.txt +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/requires.txt +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/detkit_cli.egg-info/top_level.txt +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/examples/rules/powershell_encoded_command.test.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/examples/rules/powershell_encoded_command.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/examples/rules/whoami_execution.test.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/examples/rules/whoami_execution.yml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/pyproject.toml +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/setup.cfg +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/tests/test_cli_json.py +0 -0
- {detkit_cli-0.1.5 → detkit_cli-0.1.6}/tests/test_evaluator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: detkit-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: dbt for detections — test, validate, and CI-gate Sigma detection rules as code.
|
|
5
5
|
Author: detkit
|
|
6
6
|
License-Expression: MIT
|
|
@@ -105,11 +105,28 @@ repos:
|
|
|
105
105
|
|
|
106
106
|
There's a `detkit-validate` hook too, for the lighter structural check.
|
|
107
107
|
|
|
108
|
+
## Coverage
|
|
109
|
+
|
|
110
|
+
Past a handful of rules you want to see what you're *not* covering. `detkit docs` builds a single self-contained HTML page: a catalog of every rule plus a MITRE ATT&CK heatmap of which techniques you detect, which you test, and which are gaps.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
detkit docs rules -o coverage.html
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Green is a technique with a tested rule, amber is a rule with no test, and the faint cells are the gaps. It's one file with no external assets, so you can commit it or publish it to GitHub Pages.
|
|
117
|
+
|
|
118
|
+
`detkit navigator` exports the same coverage as a [MITRE ATT&CK Navigator](https://mitre-attack.github.io/attack-navigator/) layer, so it drops straight into the tool your team already uses:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
detkit navigator rules -o coverage.json
|
|
122
|
+
# then Open Existing Layer -> Upload at the Navigator
|
|
123
|
+
```
|
|
124
|
+
|
|
108
125
|
## What it handles
|
|
109
126
|
|
|
110
|
-
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, keyword lists, and `X of` / `all of` conditions.
|
|
127
|
+
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, nested/dotted fields (`DeviceDetail.deviceId`), keyword lists, and `X of` / `all of` conditions.
|
|
111
128
|
|
|
112
|
-
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like
|
|
129
|
+
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like `base64`/`windash` modifiers or arrays of objects, `test` and `validate` print a WARN naming the feature instead of returning an answer that might be wrong. A detection tool that's quietly wrong is worse than no tool.
|
|
113
130
|
|
|
114
131
|
## Why
|
|
115
132
|
|
|
@@ -117,7 +134,7 @@ Detections live in Git now, but the testing habit that comes with the rest of so
|
|
|
117
134
|
|
|
118
135
|
## Roadmap
|
|
119
136
|
|
|
120
|
-
-
|
|
137
|
+
- `base64`/`windash` modifiers and arrays of objects (what it warns on today), probably via [pySigma](https://github.com/SigmaHQ/pySigma).
|
|
121
138
|
- `detkit generate`: draft a rule and its tests from a plain-English description. The tests come with it, not as an afterthought.
|
|
122
139
|
- Field mapping, so one rule can be checked against more than one log schema.
|
|
123
140
|
- A hosted option down the line for teams that want shared runs and history. The CLI stays free.
|
|
@@ -84,11 +84,28 @@ repos:
|
|
|
84
84
|
|
|
85
85
|
There's a `detkit-validate` hook too, for the lighter structural check.
|
|
86
86
|
|
|
87
|
+
## Coverage
|
|
88
|
+
|
|
89
|
+
Past a handful of rules you want to see what you're *not* covering. `detkit docs` builds a single self-contained HTML page: a catalog of every rule plus a MITRE ATT&CK heatmap of which techniques you detect, which you test, and which are gaps.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
detkit docs rules -o coverage.html
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Green is a technique with a tested rule, amber is a rule with no test, and the faint cells are the gaps. It's one file with no external assets, so you can commit it or publish it to GitHub Pages.
|
|
96
|
+
|
|
97
|
+
`detkit navigator` exports the same coverage as a [MITRE ATT&CK Navigator](https://mitre-attack.github.io/attack-navigator/) layer, so it drops straight into the tool your team already uses:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
detkit navigator rules -o coverage.json
|
|
101
|
+
# then Open Existing Layer -> Upload at the Navigator
|
|
102
|
+
```
|
|
103
|
+
|
|
87
104
|
## What it handles
|
|
88
105
|
|
|
89
|
-
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, keyword lists, and `X of` / `all of` conditions.
|
|
106
|
+
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, nested/dotted fields (`DeviceDetail.deviceId`), keyword lists, and `X of` / `all of` conditions.
|
|
90
107
|
|
|
91
|
-
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like
|
|
108
|
+
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like `base64`/`windash` modifiers or arrays of objects, `test` and `validate` print a WARN naming the feature instead of returning an answer that might be wrong. A detection tool that's quietly wrong is worse than no tool.
|
|
92
109
|
|
|
93
110
|
## Why
|
|
94
111
|
|
|
@@ -96,7 +113,7 @@ Detections live in Git now, but the testing habit that comes with the rest of so
|
|
|
96
113
|
|
|
97
114
|
## Roadmap
|
|
98
115
|
|
|
99
|
-
-
|
|
116
|
+
- `base64`/`windash` modifiers and arrays of objects (what it warns on today), probably via [pySigma](https://github.com/SigmaHQ/pySigma).
|
|
100
117
|
- `detkit generate`: draft a rule and its tests from a plain-English description. The tests come with it, not as an afterthought.
|
|
101
118
|
- Field mapping, so one rule can be checked against more than one log schema.
|
|
102
119
|
- A hosted option down the line for teams that want shared runs and history. The CLI stays free.
|
|
@@ -272,6 +272,23 @@ def cmd_docs(args):
|
|
|
272
272
|
return 0
|
|
273
273
|
|
|
274
274
|
|
|
275
|
+
def cmd_navigator(args):
|
|
276
|
+
rules = _discover_rules(args.path)
|
|
277
|
+
if not rules:
|
|
278
|
+
print(f"no rules found under {args.path!r}")
|
|
279
|
+
return 1
|
|
280
|
+
items = [
|
|
281
|
+
{"path": rp, "rule": _load_yaml(rp) or {}, "has_tests": _test_file_for(rp) is not None}
|
|
282
|
+
for rp in rules
|
|
283
|
+
]
|
|
284
|
+
layer = docs.navigator_layer(items, _load_attack_data())
|
|
285
|
+
with open(args.output, "w", encoding="utf-8") as f:
|
|
286
|
+
json.dump(layer, f, indent=2)
|
|
287
|
+
print(f"exported {len(layer['techniques'])} techniques -> {args.output}")
|
|
288
|
+
print("import it at https://mitre-attack.github.io/attack-navigator/ (Open Existing Layer -> Upload)")
|
|
289
|
+
return 0
|
|
290
|
+
|
|
291
|
+
|
|
275
292
|
def cmd_generate(args):
|
|
276
293
|
print(
|
|
277
294
|
"`detkit generate` is not implemented yet.\n"
|
|
@@ -307,6 +324,11 @@ def main(argv=None):
|
|
|
307
324
|
p_docs.add_argument("-o", "--output", default="detkit-docs.html")
|
|
308
325
|
p_docs.set_defaults(func=cmd_docs)
|
|
309
326
|
|
|
327
|
+
p_nav = sub.add_parser("navigator", help="export coverage as a MITRE ATT&CK Navigator layer (JSON)")
|
|
328
|
+
p_nav.add_argument("path", nargs="?", default=".")
|
|
329
|
+
p_nav.add_argument("-o", "--output", default="detkit-navigator.json")
|
|
330
|
+
p_nav.set_defaults(func=cmd_navigator)
|
|
331
|
+
|
|
310
332
|
p_gen = sub.add_parser("generate", help="(planned) AI-draft a rule + tests")
|
|
311
333
|
p_gen.set_defaults(func=cmd_generate)
|
|
312
334
|
|
|
@@ -124,6 +124,54 @@ def render(items, attack_data=None):
|
|
|
124
124
|
return _page(rules, covered, other, full, names, matrix_on, summary), summary
|
|
125
125
|
|
|
126
126
|
|
|
127
|
+
def _covered_by_technique(items):
|
|
128
|
+
"""{parent technique id: tested?} across all rules — folds sub-techniques to parent."""
|
|
129
|
+
out = {}
|
|
130
|
+
for it in items:
|
|
131
|
+
r = _extract(it)
|
|
132
|
+
for tech in r["techniques"]:
|
|
133
|
+
parent = tech.split(".")[0]
|
|
134
|
+
out[parent] = out.get(parent, False) or r["has_tests"]
|
|
135
|
+
return out
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def navigator_layer(items, attack_data=None, name="detkit coverage"):
|
|
139
|
+
"""Build a MITRE ATT&CK Navigator layer (dict) from rule coverage.
|
|
140
|
+
|
|
141
|
+
score 100 = has detkit tests (green), 50 = covered but untested (amber);
|
|
142
|
+
gaps are left out so Navigator shows them uncolored. Import at
|
|
143
|
+
https://mitre-attack.github.io/attack-navigator/.
|
|
144
|
+
"""
|
|
145
|
+
covered = _covered_by_technique(items)
|
|
146
|
+
full, _ = _matrix(attack_data)
|
|
147
|
+
universe = {t for techs in full.values() for t in techs}
|
|
148
|
+
version = str((attack_data or {}).get("attack_version", "")).lstrip("vV") or "17"
|
|
149
|
+
techniques = [
|
|
150
|
+
{
|
|
151
|
+
"techniqueID": tech,
|
|
152
|
+
"score": 100 if tested else 50,
|
|
153
|
+
"enabled": True,
|
|
154
|
+
"comment": "tested" if tested else "covered (no detkit test)",
|
|
155
|
+
}
|
|
156
|
+
for tech, tested in sorted(covered.items())
|
|
157
|
+
if not universe or tech in universe
|
|
158
|
+
]
|
|
159
|
+
return {
|
|
160
|
+
"name": name,
|
|
161
|
+
"domain": "enterprise-attack",
|
|
162
|
+
"description": "detkit detection coverage. score 100 = has detkit tests, 50 = covered but untested.",
|
|
163
|
+
"versions": {"attack": version, "navigator": "5.1.0", "layer": "4.5"},
|
|
164
|
+
"sorting": 0,
|
|
165
|
+
"hideDisabled": False,
|
|
166
|
+
"techniques": techniques,
|
|
167
|
+
"gradient": {"colors": ["#fff8c5", "#8ec843"], "minValue": 50, "maxValue": 100},
|
|
168
|
+
"legendItems": [
|
|
169
|
+
{"label": "covered, no test", "color": "#fff8c5"},
|
|
170
|
+
{"label": "tested", "color": "#8ec843"},
|
|
171
|
+
],
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
127
175
|
def _cells(cov, official, names):
|
|
128
176
|
"""cov: {tech: tested?}. official: {tech: name} (full matrix) or None."""
|
|
129
177
|
if official is None: # v1: only covered techniques
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "detkit coverage",
|
|
3
|
+
"domain": "enterprise-attack",
|
|
4
|
+
"description": "detkit detection coverage. score 100 = has detkit tests, 50 = covered but untested.",
|
|
5
|
+
"versions": {
|
|
6
|
+
"attack": "19",
|
|
7
|
+
"navigator": "5.1.0",
|
|
8
|
+
"layer": "4.5"
|
|
9
|
+
},
|
|
10
|
+
"sorting": 0,
|
|
11
|
+
"hideDisabled": false,
|
|
12
|
+
"techniques": [
|
|
13
|
+
{
|
|
14
|
+
"techniqueID": "T1027",
|
|
15
|
+
"score": 100,
|
|
16
|
+
"enabled": true,
|
|
17
|
+
"comment": "tested"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"techniqueID": "T1033",
|
|
21
|
+
"score": 100,
|
|
22
|
+
"enabled": true,
|
|
23
|
+
"comment": "tested"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"techniqueID": "T1059",
|
|
27
|
+
"score": 100,
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"comment": "tested"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"gradient": {
|
|
33
|
+
"colors": [
|
|
34
|
+
"#fff8c5",
|
|
35
|
+
"#8ec843"
|
|
36
|
+
],
|
|
37
|
+
"minValue": 50,
|
|
38
|
+
"maxValue": 100
|
|
39
|
+
},
|
|
40
|
+
"legendItems": [
|
|
41
|
+
{
|
|
42
|
+
"label": "covered, no test",
|
|
43
|
+
"color": "#fff8c5"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"label": "tested",
|
|
47
|
+
"color": "#8ec843"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: detkit-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: dbt for detections — test, validate, and CI-gate Sigma detection rules as code.
|
|
5
5
|
Author: detkit
|
|
6
6
|
License-Expression: MIT
|
|
@@ -105,11 +105,28 @@ repos:
|
|
|
105
105
|
|
|
106
106
|
There's a `detkit-validate` hook too, for the lighter structural check.
|
|
107
107
|
|
|
108
|
+
## Coverage
|
|
109
|
+
|
|
110
|
+
Past a handful of rules you want to see what you're *not* covering. `detkit docs` builds a single self-contained HTML page: a catalog of every rule plus a MITRE ATT&CK heatmap of which techniques you detect, which you test, and which are gaps.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
detkit docs rules -o coverage.html
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Green is a technique with a tested rule, amber is a rule with no test, and the faint cells are the gaps. It's one file with no external assets, so you can commit it or publish it to GitHub Pages.
|
|
117
|
+
|
|
118
|
+
`detkit navigator` exports the same coverage as a [MITRE ATT&CK Navigator](https://mitre-attack.github.io/attack-navigator/) layer, so it drops straight into the tool your team already uses:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
detkit navigator rules -o coverage.json
|
|
122
|
+
# then Open Existing Layer -> Upload at the Navigator
|
|
123
|
+
```
|
|
124
|
+
|
|
108
125
|
## What it handles
|
|
109
126
|
|
|
110
|
-
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, keyword lists, and `X of` / `all of` conditions.
|
|
127
|
+
detkit runs your rules locally. No SIEM, no credentials, nothing leaves your machine or CI runner. I ran it against every rule in the SigmaHQ repo, and about 91% use only features it understands today: `contains`, `startswith`, `endswith`, `re`, value wildcards (`*` and `?`), `|cidr`, nested/dotted fields (`DeviceDetail.deviceId`), keyword lists, and `X of` / `all of` conditions.
|
|
111
128
|
|
|
112
|
-
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like
|
|
129
|
+
It won't guess at the rest. If a rule uses something detkit can't evaluate yet, like `base64`/`windash` modifiers or arrays of objects, `test` and `validate` print a WARN naming the feature instead of returning an answer that might be wrong. A detection tool that's quietly wrong is worse than no tool.
|
|
113
130
|
|
|
114
131
|
## Why
|
|
115
132
|
|
|
@@ -117,7 +134,7 @@ Detections live in Git now, but the testing habit that comes with the rest of so
|
|
|
117
134
|
|
|
118
135
|
## Roadmap
|
|
119
136
|
|
|
120
|
-
-
|
|
137
|
+
- `base64`/`windash` modifiers and arrays of objects (what it warns on today), probably via [pySigma](https://github.com/SigmaHQ/pySigma).
|
|
121
138
|
- `detkit generate`: draft a rule and its tests from a plain-English description. The tests come with it, not as an afterthought.
|
|
122
139
|
- Field mapping, so one rule can be checked against more than one log schema.
|
|
123
140
|
- A hosted option down the line for teams that want shared runs and history. The CLI stays free.
|
|
@@ -4,7 +4,7 @@ import sys
|
|
|
4
4
|
|
|
5
5
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
6
6
|
|
|
7
|
-
from detkit.docs import parse_attack, render # noqa: E402
|
|
7
|
+
from detkit.docs import navigator_layer, parse_attack, render # noqa: E402
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def test_parse_attack():
|
|
@@ -39,6 +39,25 @@ def test_render_empty():
|
|
|
39
39
|
assert "<!doctype html>" in html_str.lower()
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def test_navigator_layer():
|
|
43
|
+
items = [
|
|
44
|
+
{"path": "a.yml", "has_tests": True,
|
|
45
|
+
"rule": {"title": "A", "tags": ["attack.execution", "attack.t1059.001"]}},
|
|
46
|
+
{"path": "b.yml", "has_tests": False,
|
|
47
|
+
"rule": {"title": "B", "tags": ["attack.persistence", "attack.t1547"]}},
|
|
48
|
+
]
|
|
49
|
+
attack = {"attack_version": "v19", "techniques": [
|
|
50
|
+
{"id": "T1059", "name": "x", "tactics": ["execution"]},
|
|
51
|
+
{"id": "T1547", "name": "y", "tactics": ["persistence"]},
|
|
52
|
+
]}
|
|
53
|
+
layer = navigator_layer(items, attack)
|
|
54
|
+
assert layer["domain"] == "enterprise-attack"
|
|
55
|
+
assert layer["versions"]["attack"] == "19" # 'v19' -> '19'
|
|
56
|
+
by = {t["techniqueID"]: t for t in layer["techniques"]}
|
|
57
|
+
assert by["T1059"]["score"] == 100 # sub-technique folds to parent, tested
|
|
58
|
+
assert by["T1547"]["score"] == 50 # covered, no test
|
|
59
|
+
|
|
60
|
+
|
|
42
61
|
if __name__ == "__main__":
|
|
43
62
|
fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
|
|
44
63
|
for fn in fns:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|