agentic-threat-hunting-framework 0.2.2__py3-none-any.whl → 0.2.3__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-threat-hunting-framework
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Agentic Threat Hunting Framework - Memory and AI for threat hunters
5
5
  Author-email: Sydney Marrone <athf@nebulock.io>
6
6
  Maintainer-email: Sydney Marrone <athf@nebulock.io>
@@ -1,9 +1,9 @@
1
- agentic_threat_hunting_framework-0.2.2.dist-info/licenses/LICENSE,sha256=_KObErRfiKoolznt-DF0nJnr3U9Rdh7Z4Ba7G5qqckk,1071
1
+ agentic_threat_hunting_framework-0.2.3.dist-info/licenses/LICENSE,sha256=_KObErRfiKoolznt-DF0nJnr3U9Rdh7Z4Ba7G5qqckk,1071
2
2
  athf/__init__.py,sha256=OrjZe8P97_BTEkscapnwSsqKSjwXNP9d8-HtGr19Ni0,241
3
3
  athf/__version__.py,sha256=p9cAuZ-dTEMpo-qoeYkFo2166r8LvKpa5qHBZihGq3w,59
4
4
  athf/cli.py,sha256=XLNRXEs9kHPH6utJ7_SnzLFcldbGAnACPMTe0xMOkhQ,4492
5
5
  athf/commands/__init__.py,sha256=uDyr0bz-agpGO8fraXQl24wuQCxqbeCevZsJ2bDK29s,25
6
- athf/commands/context.py,sha256=XpMtTf9Pq6NxMhawp6f1NYnTKYt1IuGx9CNDIY8K8Do,11956
6
+ athf/commands/context.py,sha256=WvOf0OuttAsEk_h4QDtdfqYI4CulDg2UCtq_5r5iJAA,12686
7
7
  athf/commands/env.py,sha256=AisRllJXbyCjK_2ii21qBBmCz9raxhBUemwM7BxqIYg,11859
8
8
  athf/commands/hunt.py,sha256=2KORNWAqEvLY-Wc1q-a894g8kOpcqw_iJfnenKJeTDI,23019
9
9
  athf/commands/init.py,sha256=L_29fvZF8SZ1BKh2D6NyDuacCC5JXOTezIxdBnnK88E,10941
@@ -11,13 +11,13 @@ athf/commands/investigate.py,sha256=mK_id5vjfN_ukqB_-fyia0FNa0pBmtn0Xv6CKHQI1Qo,
11
11
  athf/commands/similar.py,sha256=ROoMs4NP1otCaXwM1XzpLWxmANknoeASlBT7zuMDqas,11793
12
12
  athf/core/__init__.py,sha256=yG7C8ljx3UW4QZoYvDjUxsWHlbS8M-GLGB7Je7rRfqo,31
13
13
  athf/core/attack_matrix.py,sha256=QZKKmxckQ6-U7lqVdGUJoj2jEAhP3Juvr3sqaNx2oTw,3238
14
- athf/core/hunt_manager.py,sha256=6DC3wmreJ5IBiC7vi9xB9DP_WDXOetmGceFPTqjYVRU,11366
14
+ athf/core/hunt_manager.py,sha256=PFsg8Ecg94NCpuFZpApo82lyORkgK5IfOIih-7-XsmM,11580
15
15
  athf/core/hunt_parser.py,sha256=FUj0yyBIcZnaS9aItMImeBDhegQwpkewIwUMNXW_ZWU,5122
16
16
  athf/core/investigation_parser.py,sha256=wbfjnq4gFgIc0a4bHIAnidVNPhbHDpIXWY1SGLk0Xls,6804
17
17
  athf/core/template_engine.py,sha256=vNTVhlxIXZpxU7VmQyrqCSt6ORS0IVjAV54TOmUDMTE,5636
18
18
  athf/utils/__init__.py,sha256=aEAPI1xnAsowOtc036cCb9ZOek5nrrfevu8PElhbNgk,30
19
- agentic_threat_hunting_framework-0.2.2.dist-info/METADATA,sha256=zFr9-YmLEz0jqC0rmqEUmOmMhl-yMUr20U9IrqUrfcI,15472
20
- agentic_threat_hunting_framework-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- agentic_threat_hunting_framework-0.2.2.dist-info/entry_points.txt,sha256=GopR2iTiBs-yNMWiUZ2DaFIFglXxWJx1XPjTa3ePtfE,39
22
- agentic_threat_hunting_framework-0.2.2.dist-info/top_level.txt,sha256=Cxxg6SMLfawDJWBITsciRzq27XV8fiaAor23o9Byoes,5
23
- agentic_threat_hunting_framework-0.2.2.dist-info/RECORD,,
19
+ agentic_threat_hunting_framework-0.2.3.dist-info/METADATA,sha256=I3x8s2Rff1A7BjYz-lfy_M6I_qw0-nDBC2Ypc0DcxTA,15472
20
+ agentic_threat_hunting_framework-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ agentic_threat_hunting_framework-0.2.3.dist-info/entry_points.txt,sha256=GopR2iTiBs-yNMWiUZ2DaFIFglXxWJx1XPjTa3ePtfE,39
22
+ agentic_threat_hunting_framework-0.2.3.dist-info/top_level.txt,sha256=Cxxg6SMLfawDJWBITsciRzq27XV8fiaAor23o9Byoes,5
23
+ agentic_threat_hunting_framework-0.2.3.dist-info/RECORD,,
athf/commands/context.py CHANGED
@@ -22,6 +22,9 @@ Examples:
22
22
  # Export context for macOS platform hunts
23
23
  athf context --platform macos
24
24
 
25
+ # Combine filters: persistence hunts on Linux
26
+ athf context --tactic persistence --platform linux
27
+
25
28
  # Export full repository context (large output)
26
29
  athf context --full
27
30
 
@@ -86,18 +89,20 @@ def context(
86
89
  • With context: 1 command, ~1,000 tokens
87
90
  • Savings: ~2,000 tokens per hunt (~$0.03 per hunt)
88
91
  """
89
- # Validate mutually exclusive options
90
- exclusive_options = sum([bool(hunt), bool(tactic), bool(platform), full])
91
- if exclusive_options == 0:
92
- console.print("[red]Error: Must specify one of: --hunt, --tactic, --platform, or --full[/red]")
92
+ # Validate that at least one filter is provided
93
+ has_filter = any([hunt, tactic, platform, full])
94
+ if not has_filter:
95
+ console.print("[red]Error: Must specify at least one of: --hunt, --tactic, --platform, or --full[/red]")
93
96
  console.print("\n[dim]Examples:[/dim]")
94
97
  console.print(" athf context --hunt H-0013")
95
98
  console.print(" athf context --tactic credential-access")
96
99
  console.print(" athf context --platform macos")
100
+ console.print(" athf context --tactic persistence --platform linux")
97
101
  raise click.Abort()
98
102
 
99
- if exclusive_options > 1:
100
- console.print("[red]Error: Only one filter option allowed at a time[/red]")
103
+ # --full flag is mutually exclusive with other filters
104
+ if full and (hunt or tactic or platform):
105
+ console.print("[red]Error: --full cannot be combined with other filters[/red]")
101
106
  raise click.Abort()
102
107
 
103
108
  # Build context bundle
@@ -158,17 +163,26 @@ def _build_context(
158
163
  if index_path.exists():
159
164
  context["hunt_index"] = _read_and_optimize(index_path)
160
165
 
161
- # Load hunts based on filter
162
- if hunt:
163
- hunt_files = [Path(f"hunts/{hunt}.md")]
164
- elif tactic:
165
- hunt_files = _find_hunts_by_tactic(tactic)
166
- elif platform:
167
- hunt_files = _find_hunts_by_platform(platform)
168
- elif full:
166
+ # Load hunts based on filters (can be combined)
167
+ if full:
168
+ # Full export: include all hunts
169
169
  hunt_files = list(Path("hunts").glob("H-*.md"))
170
+ elif hunt:
171
+ # Specific hunt: only load that one
172
+ hunt_files = [Path(f"hunts/{hunt}.md")]
170
173
  else:
171
- hunt_files = []
174
+ # Combine tactic and platform filters
175
+ if tactic and platform:
176
+ # Both filters: find hunts matching both criteria
177
+ tactic_hunts = set(_find_hunts_by_tactic(tactic))
178
+ platform_hunts = set(_find_hunts_by_platform(platform))
179
+ hunt_files = list(tactic_hunts & platform_hunts) # Intersection
180
+ elif tactic:
181
+ hunt_files = _find_hunts_by_tactic(tactic)
182
+ elif platform:
183
+ hunt_files = _find_hunts_by_platform(platform)
184
+ else:
185
+ hunt_files = []
172
186
 
173
187
  # Load hunt content
174
188
  for hunt_file in hunt_files:
athf/core/hunt_manager.py CHANGED
@@ -154,7 +154,14 @@ class HuntManager:
154
154
  results = []
155
155
  query_lower = query.lower()
156
156
 
157
+ # Exclude documentation files
158
+ exclude_files = {"README.md", "FORMAT_GUIDELINES.md"}
159
+
157
160
  for hunt_file in self.hunts_dir.glob("*.md"):
161
+ # Skip documentation files
162
+ if hunt_file.name in exclude_files:
163
+ continue
164
+
158
165
  try:
159
166
  with open(hunt_file, "r", encoding="utf-8") as f:
160
167
  content = f.read()