hackagent 0.3.1__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.
- hackagent/__init__.py +12 -0
- hackagent/agent.py +214 -0
- hackagent/api/__init__.py +1 -0
- hackagent/api/agent/__init__.py +1 -0
- hackagent/api/agent/agent_create.py +347 -0
- hackagent/api/agent/agent_destroy.py +140 -0
- hackagent/api/agent/agent_list.py +242 -0
- hackagent/api/agent/agent_partial_update.py +361 -0
- hackagent/api/agent/agent_retrieve.py +235 -0
- hackagent/api/agent/agent_update.py +361 -0
- hackagent/api/apilogs/__init__.py +1 -0
- hackagent/api/apilogs/apilogs_list.py +170 -0
- hackagent/api/apilogs/apilogs_retrieve.py +162 -0
- hackagent/api/attack/__init__.py +1 -0
- hackagent/api/attack/attack_create.py +275 -0
- hackagent/api/attack/attack_destroy.py +146 -0
- hackagent/api/attack/attack_list.py +254 -0
- hackagent/api/attack/attack_partial_update.py +289 -0
- hackagent/api/attack/attack_retrieve.py +247 -0
- hackagent/api/attack/attack_update.py +289 -0
- hackagent/api/checkout/__init__.py +1 -0
- hackagent/api/checkout/checkout_create.py +225 -0
- hackagent/api/generate/__init__.py +1 -0
- hackagent/api/generate/generate_create.py +253 -0
- hackagent/api/judge/__init__.py +1 -0
- hackagent/api/judge/judge_create.py +253 -0
- hackagent/api/key/__init__.py +1 -0
- hackagent/api/key/key_create.py +179 -0
- hackagent/api/key/key_destroy.py +103 -0
- hackagent/api/key/key_list.py +170 -0
- hackagent/api/key/key_retrieve.py +162 -0
- hackagent/api/organization/__init__.py +1 -0
- hackagent/api/organization/organization_create.py +208 -0
- hackagent/api/organization/organization_destroy.py +104 -0
- hackagent/api/organization/organization_list.py +170 -0
- hackagent/api/organization/organization_me_retrieve.py +126 -0
- hackagent/api/organization/organization_partial_update.py +222 -0
- hackagent/api/organization/organization_retrieve.py +163 -0
- hackagent/api/organization/organization_update.py +222 -0
- hackagent/api/prompt/__init__.py +1 -0
- hackagent/api/prompt/prompt_create.py +171 -0
- hackagent/api/prompt/prompt_destroy.py +104 -0
- hackagent/api/prompt/prompt_list.py +185 -0
- hackagent/api/prompt/prompt_partial_update.py +185 -0
- hackagent/api/prompt/prompt_retrieve.py +163 -0
- hackagent/api/prompt/prompt_update.py +185 -0
- hackagent/api/result/__init__.py +1 -0
- hackagent/api/result/result_create.py +175 -0
- hackagent/api/result/result_destroy.py +106 -0
- hackagent/api/result/result_list.py +249 -0
- hackagent/api/result/result_partial_update.py +193 -0
- hackagent/api/result/result_retrieve.py +167 -0
- hackagent/api/result/result_trace_create.py +177 -0
- hackagent/api/result/result_update.py +189 -0
- hackagent/api/run/__init__.py +1 -0
- hackagent/api/run/run_create.py +187 -0
- hackagent/api/run/run_destroy.py +112 -0
- hackagent/api/run/run_list.py +291 -0
- hackagent/api/run/run_partial_update.py +201 -0
- hackagent/api/run/run_result_create.py +177 -0
- hackagent/api/run/run_retrieve.py +179 -0
- hackagent/api/run/run_run_tests_create.py +187 -0
- hackagent/api/run/run_update.py +201 -0
- hackagent/api/user/__init__.py +1 -0
- hackagent/api/user/user_create.py +212 -0
- hackagent/api/user/user_destroy.py +106 -0
- hackagent/api/user/user_list.py +174 -0
- hackagent/api/user/user_me_retrieve.py +126 -0
- hackagent/api/user/user_me_update.py +196 -0
- hackagent/api/user/user_partial_update.py +226 -0
- hackagent/api/user/user_retrieve.py +167 -0
- hackagent/api/user/user_update.py +226 -0
- hackagent/attacks/AdvPrefix/__init__.py +41 -0
- hackagent/attacks/AdvPrefix/completions.py +416 -0
- hackagent/attacks/AdvPrefix/config.py +259 -0
- hackagent/attacks/AdvPrefix/evaluation.py +745 -0
- hackagent/attacks/AdvPrefix/evaluators.py +564 -0
- hackagent/attacks/AdvPrefix/generate.py +711 -0
- hackagent/attacks/AdvPrefix/utils.py +307 -0
- hackagent/attacks/__init__.py +35 -0
- hackagent/attacks/advprefix.py +507 -0
- hackagent/attacks/base.py +106 -0
- hackagent/attacks/strategies.py +906 -0
- hackagent/cli/__init__.py +19 -0
- hackagent/cli/commands/__init__.py +20 -0
- hackagent/cli/commands/agent.py +100 -0
- hackagent/cli/commands/attack.py +417 -0
- hackagent/cli/commands/config.py +301 -0
- hackagent/cli/commands/results.py +327 -0
- hackagent/cli/config.py +249 -0
- hackagent/cli/main.py +515 -0
- hackagent/cli/tui/__init__.py +31 -0
- hackagent/cli/tui/actions_logger.py +200 -0
- hackagent/cli/tui/app.py +288 -0
- hackagent/cli/tui/base.py +137 -0
- hackagent/cli/tui/logger.py +318 -0
- hackagent/cli/tui/views/__init__.py +33 -0
- hackagent/cli/tui/views/agents.py +488 -0
- hackagent/cli/tui/views/attacks.py +624 -0
- hackagent/cli/tui/views/config.py +244 -0
- hackagent/cli/tui/views/dashboard.py +307 -0
- hackagent/cli/tui/views/results.py +1210 -0
- hackagent/cli/tui/widgets/__init__.py +24 -0
- hackagent/cli/tui/widgets/actions.py +346 -0
- hackagent/cli/tui/widgets/logs.py +435 -0
- hackagent/cli/utils.py +276 -0
- hackagent/client.py +286 -0
- hackagent/errors.py +37 -0
- hackagent/logger.py +83 -0
- hackagent/models/__init__.py +109 -0
- hackagent/models/agent.py +223 -0
- hackagent/models/agent_request.py +129 -0
- hackagent/models/api_token_log.py +184 -0
- hackagent/models/attack.py +154 -0
- hackagent/models/attack_request.py +82 -0
- hackagent/models/checkout_session_request_request.py +76 -0
- hackagent/models/checkout_session_response.py +59 -0
- hackagent/models/choice.py +81 -0
- hackagent/models/choice_message.py +67 -0
- hackagent/models/evaluation_status_enum.py +14 -0
- hackagent/models/generate_error_response.py +59 -0
- hackagent/models/generate_request_request.py +212 -0
- hackagent/models/generate_success_response.py +115 -0
- hackagent/models/generic_error_response.py +70 -0
- hackagent/models/message_request.py +67 -0
- hackagent/models/organization.py +102 -0
- hackagent/models/organization_minimal.py +68 -0
- hackagent/models/organization_request.py +71 -0
- hackagent/models/paginated_agent_list.py +123 -0
- hackagent/models/paginated_api_token_log_list.py +123 -0
- hackagent/models/paginated_attack_list.py +123 -0
- hackagent/models/paginated_organization_list.py +123 -0
- hackagent/models/paginated_prompt_list.py +123 -0
- hackagent/models/paginated_result_list.py +123 -0
- hackagent/models/paginated_run_list.py +123 -0
- hackagent/models/paginated_user_api_key_list.py +123 -0
- hackagent/models/paginated_user_profile_list.py +123 -0
- hackagent/models/patched_agent_request.py +128 -0
- hackagent/models/patched_attack_request.py +92 -0
- hackagent/models/patched_organization_request.py +71 -0
- hackagent/models/patched_prompt_request.py +125 -0
- hackagent/models/patched_result_request.py +237 -0
- hackagent/models/patched_run_request.py +138 -0
- hackagent/models/patched_user_profile_request.py +99 -0
- hackagent/models/prompt.py +220 -0
- hackagent/models/prompt_request.py +126 -0
- hackagent/models/result.py +294 -0
- hackagent/models/result_list_evaluation_status.py +14 -0
- hackagent/models/result_request.py +232 -0
- hackagent/models/run.py +233 -0
- hackagent/models/run_list_status.py +12 -0
- hackagent/models/run_request.py +133 -0
- hackagent/models/status_enum.py +12 -0
- hackagent/models/step_type_enum.py +14 -0
- hackagent/models/trace.py +121 -0
- hackagent/models/trace_request.py +94 -0
- hackagent/models/usage.py +75 -0
- hackagent/models/user_api_key.py +201 -0
- hackagent/models/user_api_key_request.py +73 -0
- hackagent/models/user_profile.py +135 -0
- hackagent/models/user_profile_minimal.py +76 -0
- hackagent/models/user_profile_request.py +99 -0
- hackagent/router/__init__.py +25 -0
- hackagent/router/adapters/__init__.py +20 -0
- hackagent/router/adapters/base.py +63 -0
- hackagent/router/adapters/google_adk.py +671 -0
- hackagent/router/adapters/litellm_adapter.py +524 -0
- hackagent/router/adapters/openai_adapter.py +426 -0
- hackagent/router/router.py +969 -0
- hackagent/router/types.py +54 -0
- hackagent/tracking/__init__.py +42 -0
- hackagent/tracking/context.py +163 -0
- hackagent/tracking/decorators.py +299 -0
- hackagent/tracking/tracker.py +441 -0
- hackagent/types.py +54 -0
- hackagent/utils.py +194 -0
- hackagent/vulnerabilities/__init__.py +13 -0
- hackagent/vulnerabilities/prompts.py +81 -0
- hackagent-0.3.1.dist-info/METADATA +122 -0
- hackagent-0.3.1.dist-info/RECORD +183 -0
- hackagent-0.3.1.dist-info/WHEEL +4 -0
- hackagent-0.3.1.dist-info/entry_points.txt +2 -0
- hackagent-0.3.1.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Copyright 2025 - AI4I. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
TUI Logging Handler and Decorator
|
|
17
|
+
|
|
18
|
+
This module provides a thread-safe logging system for displaying attack
|
|
19
|
+
execution logs in the TUI. It includes:
|
|
20
|
+
- A custom logging handler that captures logs for TUI display
|
|
21
|
+
- A decorator that can be applied to any attack's run() method
|
|
22
|
+
- Thread-safe log transmission to the TUI
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import functools
|
|
26
|
+
import logging
|
|
27
|
+
import threading
|
|
28
|
+
from collections import deque
|
|
29
|
+
from typing import Any, Callable, Deque, Optional, TypeVar, cast
|
|
30
|
+
|
|
31
|
+
from textual.app import App
|
|
32
|
+
|
|
33
|
+
# Type variable for preserving function signatures
|
|
34
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TUILogHandler(logging.Handler):
|
|
38
|
+
"""
|
|
39
|
+
Thread-safe logging handler that captures logs for TUI display.
|
|
40
|
+
|
|
41
|
+
This handler captures log records and transmits them to the TUI
|
|
42
|
+
via a thread-safe callback mechanism. It supports:
|
|
43
|
+
- Thread-safe log transmission
|
|
44
|
+
- Log level filtering
|
|
45
|
+
- Bounded buffer to prevent memory overflow
|
|
46
|
+
- Graceful handling of TUI disconnection
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
app: Optional[App] = None,
|
|
52
|
+
callback: Optional[Callable[[str, str], None]] = None,
|
|
53
|
+
max_buffer_size: int = 1000,
|
|
54
|
+
level: int = logging.INFO,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
Initialize the TUI log handler.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
app: Textual App instance for thread-safe calls
|
|
61
|
+
callback: Function to call with (message, level) for each log
|
|
62
|
+
max_buffer_size: Maximum number of logs to buffer
|
|
63
|
+
level: Minimum log level to capture (default: INFO)
|
|
64
|
+
"""
|
|
65
|
+
super().__init__(level=level)
|
|
66
|
+
self.app = app
|
|
67
|
+
self.callback = callback
|
|
68
|
+
self.max_buffer_size = max_buffer_size
|
|
69
|
+
self.buffer: Deque[tuple[str, str]] = deque(maxlen=max_buffer_size)
|
|
70
|
+
self._lock = threading.Lock()
|
|
71
|
+
self._active = True
|
|
72
|
+
|
|
73
|
+
# Set formatter for consistent log formatting
|
|
74
|
+
formatter = logging.Formatter(
|
|
75
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
76
|
+
datefmt="%H:%M:%S",
|
|
77
|
+
)
|
|
78
|
+
self.setFormatter(formatter)
|
|
79
|
+
|
|
80
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Emit a log record to the TUI.
|
|
83
|
+
|
|
84
|
+
This method is called by the logging system for each log entry.
|
|
85
|
+
It formats the record and transmits it to the TUI via the callback.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
record: The log record to emit
|
|
89
|
+
"""
|
|
90
|
+
if not self._active:
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
# Format the log message
|
|
95
|
+
log_entry = self.format(record)
|
|
96
|
+
level_name = record.levelname
|
|
97
|
+
|
|
98
|
+
# Store in buffer
|
|
99
|
+
with self._lock:
|
|
100
|
+
self.buffer.append((log_entry, level_name))
|
|
101
|
+
|
|
102
|
+
# Transmit to TUI if callback is available
|
|
103
|
+
if self.callback and self.app:
|
|
104
|
+
try:
|
|
105
|
+
# Use app.call_from_thread for thread-safe TUI updates
|
|
106
|
+
self.app.call_from_thread(self.callback, log_entry, level_name)
|
|
107
|
+
except Exception:
|
|
108
|
+
# If TUI callback fails, just continue (don't break logging)
|
|
109
|
+
# This could happen if the TUI is shutting down
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
except Exception:
|
|
113
|
+
# Silently ignore errors in logging to prevent cascading failures
|
|
114
|
+
self.handleError(record)
|
|
115
|
+
|
|
116
|
+
def get_buffer(self) -> list[tuple[str, str]]:
|
|
117
|
+
"""
|
|
118
|
+
Get all buffered log entries.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
List of (message, level) tuples
|
|
122
|
+
"""
|
|
123
|
+
with self._lock:
|
|
124
|
+
return list(self.buffer)
|
|
125
|
+
|
|
126
|
+
def clear_buffer(self) -> None:
|
|
127
|
+
"""Clear all buffered log entries."""
|
|
128
|
+
with self._lock:
|
|
129
|
+
self.buffer.clear()
|
|
130
|
+
|
|
131
|
+
def deactivate(self) -> None:
|
|
132
|
+
"""Deactivate the handler (stop emitting logs)."""
|
|
133
|
+
self._active = False
|
|
134
|
+
|
|
135
|
+
def activate(self) -> None:
|
|
136
|
+
"""Activate the handler (resume emitting logs)."""
|
|
137
|
+
self._active = True
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def with_tui_logging(
|
|
141
|
+
logger_name: str = "hackagent",
|
|
142
|
+
level: int = logging.INFO,
|
|
143
|
+
) -> Callable[[F], F]:
|
|
144
|
+
"""
|
|
145
|
+
Decorator that captures logs from an attack's run() method for TUI display.
|
|
146
|
+
|
|
147
|
+
This decorator can be applied to any attack class's run() method to
|
|
148
|
+
automatically capture and display logs in the TUI. It:
|
|
149
|
+
- Temporarily attaches a TUI log handler
|
|
150
|
+
- Captures logs during attack execution
|
|
151
|
+
- Removes the handler after completion
|
|
152
|
+
- Works with both sync and async methods
|
|
153
|
+
- Preserves the original return value
|
|
154
|
+
|
|
155
|
+
Usage:
|
|
156
|
+
class MyAttack(BaseAttack):
|
|
157
|
+
@with_tui_logging(logger_name="hackagent.attacks.myattack")
|
|
158
|
+
def run(self, goals: List[str]) -> pd.DataFrame:
|
|
159
|
+
# Attack logic here
|
|
160
|
+
return results
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
logger_name: Name of the logger to attach the handler to
|
|
164
|
+
level: Minimum log level to capture (default: INFO)
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Decorator function that wraps the attack's run method
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def decorator(func: F) -> F:
|
|
171
|
+
@functools.wraps(func)
|
|
172
|
+
def wrapper(self, *args: Any, **kwargs: Any) -> Any:
|
|
173
|
+
# Get the logger to attach the handler to
|
|
174
|
+
target_logger = logging.getLogger(logger_name)
|
|
175
|
+
|
|
176
|
+
# Try to get TUI log handler from the attack instance
|
|
177
|
+
tui_handler: Optional[TUILogHandler] = None
|
|
178
|
+
if hasattr(self, "_tui_log_handler"):
|
|
179
|
+
tui_handler = self._tui_log_handler
|
|
180
|
+
|
|
181
|
+
# If we have a TUI handler, attach it to the logger
|
|
182
|
+
if tui_handler:
|
|
183
|
+
tui_handler.activate()
|
|
184
|
+
target_logger.addHandler(tui_handler)
|
|
185
|
+
target_logger.setLevel(level)
|
|
186
|
+
|
|
187
|
+
# Attach to ALL child loggers under this logger hierarchy
|
|
188
|
+
# This ensures logs from submodules (e.g., AdvPrefix/*) are captured
|
|
189
|
+
for existing_logger_name in list(
|
|
190
|
+
logging.Logger.manager.loggerDict.keys()
|
|
191
|
+
):
|
|
192
|
+
if existing_logger_name.startswith(logger_name + "."):
|
|
193
|
+
child_logger = logging.getLogger(existing_logger_name)
|
|
194
|
+
if tui_handler not in child_logger.handlers:
|
|
195
|
+
child_logger.addHandler(tui_handler)
|
|
196
|
+
child_logger.setLevel(level)
|
|
197
|
+
|
|
198
|
+
# Also attach to router loggers to capture agent interactions
|
|
199
|
+
router_logger = logging.getLogger("hackagent.router")
|
|
200
|
+
if tui_handler not in router_logger.handlers:
|
|
201
|
+
router_logger.addHandler(tui_handler)
|
|
202
|
+
router_logger.setLevel(level)
|
|
203
|
+
|
|
204
|
+
# Attach to router child loggers (adapters)
|
|
205
|
+
for existing_logger_name in list(
|
|
206
|
+
logging.Logger.manager.loggerDict.keys()
|
|
207
|
+
):
|
|
208
|
+
if existing_logger_name.startswith("hackagent.router."):
|
|
209
|
+
child_logger = logging.getLogger(existing_logger_name)
|
|
210
|
+
if tui_handler not in child_logger.handlers:
|
|
211
|
+
child_logger.addHandler(tui_handler)
|
|
212
|
+
child_logger.setLevel(level)
|
|
213
|
+
|
|
214
|
+
# Also attach to the attack module logger for backward compatibility
|
|
215
|
+
attack_module_logger = logging.getLogger(self.__class__.__module__)
|
|
216
|
+
if tui_handler not in attack_module_logger.handlers:
|
|
217
|
+
attack_module_logger.addHandler(tui_handler)
|
|
218
|
+
attack_module_logger.setLevel(level)
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
# Execute the actual attack run method
|
|
222
|
+
result = func(self, *args, **kwargs)
|
|
223
|
+
return result
|
|
224
|
+
|
|
225
|
+
finally:
|
|
226
|
+
# Always remove the handler when done
|
|
227
|
+
if tui_handler:
|
|
228
|
+
tui_handler.deactivate()
|
|
229
|
+
# Remove from base logger
|
|
230
|
+
if tui_handler in target_logger.handlers:
|
|
231
|
+
target_logger.removeHandler(tui_handler)
|
|
232
|
+
|
|
233
|
+
# Remove from all child loggers under attack hierarchy
|
|
234
|
+
for existing_logger_name in list(
|
|
235
|
+
logging.Logger.manager.loggerDict.keys()
|
|
236
|
+
):
|
|
237
|
+
if existing_logger_name.startswith(logger_name + "."):
|
|
238
|
+
child_logger = logging.getLogger(existing_logger_name)
|
|
239
|
+
if tui_handler in child_logger.handlers:
|
|
240
|
+
child_logger.removeHandler(tui_handler)
|
|
241
|
+
|
|
242
|
+
# Remove from router loggers
|
|
243
|
+
router_logger = logging.getLogger("hackagent.router")
|
|
244
|
+
if tui_handler in router_logger.handlers:
|
|
245
|
+
router_logger.removeHandler(tui_handler)
|
|
246
|
+
|
|
247
|
+
for existing_logger_name in list(
|
|
248
|
+
logging.Logger.manager.loggerDict.keys()
|
|
249
|
+
):
|
|
250
|
+
if existing_logger_name.startswith("hackagent.router."):
|
|
251
|
+
child_logger = logging.getLogger(existing_logger_name)
|
|
252
|
+
if tui_handler in child_logger.handlers:
|
|
253
|
+
child_logger.removeHandler(tui_handler)
|
|
254
|
+
|
|
255
|
+
# Remove from attack module logger
|
|
256
|
+
if self.__class__.__module__:
|
|
257
|
+
attack_module_logger = logging.getLogger(
|
|
258
|
+
self.__class__.__module__
|
|
259
|
+
)
|
|
260
|
+
if tui_handler in attack_module_logger.handlers:
|
|
261
|
+
attack_module_logger.removeHandler(tui_handler)
|
|
262
|
+
|
|
263
|
+
return cast(F, wrapper)
|
|
264
|
+
|
|
265
|
+
return decorator
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def attach_tui_handler(
|
|
269
|
+
attack_instance: Any,
|
|
270
|
+
app: App,
|
|
271
|
+
callback: Callable[[str, str], None],
|
|
272
|
+
max_buffer_size: int = 1000,
|
|
273
|
+
level: int = logging.INFO,
|
|
274
|
+
) -> TUILogHandler:
|
|
275
|
+
"""
|
|
276
|
+
Attach a TUI log handler to an attack instance.
|
|
277
|
+
|
|
278
|
+
This function should be called before executing an attack to set up
|
|
279
|
+
the logging infrastructure for TUI display.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
attack_instance: The attack object to attach the handler to
|
|
283
|
+
app: Textual App instance for thread-safe calls
|
|
284
|
+
callback: Function to call with (message, level) for each log
|
|
285
|
+
max_buffer_size: Maximum number of logs to buffer
|
|
286
|
+
level: Minimum log level to capture
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
The created TUILogHandler instance
|
|
290
|
+
"""
|
|
291
|
+
handler = TUILogHandler(
|
|
292
|
+
app=app,
|
|
293
|
+
callback=callback,
|
|
294
|
+
max_buffer_size=max_buffer_size,
|
|
295
|
+
level=level,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Store the handler on the attack instance
|
|
299
|
+
attack_instance._tui_log_handler = handler
|
|
300
|
+
|
|
301
|
+
return handler
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def detach_tui_handler(attack_instance: Any) -> Optional[TUILogHandler]:
|
|
305
|
+
"""
|
|
306
|
+
Detach and return the TUI log handler from an attack instance.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
attack_instance: The attack object to detach the handler from
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
The detached TUILogHandler instance, or None if not present
|
|
313
|
+
"""
|
|
314
|
+
if hasattr(attack_instance, "_tui_log_handler"):
|
|
315
|
+
handler = attack_instance._tui_log_handler
|
|
316
|
+
delattr(attack_instance, "_tui_log_handler")
|
|
317
|
+
return handler
|
|
318
|
+
return None
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright 2025 - AI4I. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
TUI Views
|
|
17
|
+
|
|
18
|
+
Tab views/panels for the HackAgent TUI application.
|
|
19
|
+
Each view represents a different functional area of the interface.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from hackagent.cli.tui.views.agents import AgentsTab
|
|
23
|
+
from hackagent.cli.tui.views.attacks import AttacksTab
|
|
24
|
+
from hackagent.cli.tui.views.config import ConfigTab
|
|
25
|
+
from hackagent.cli.tui.views.results import ResultsTab
|
|
26
|
+
|
|
27
|
+
__all__ = ["AgentsTab", "AttacksTab", "ConfigTab", "ResultsTab"]
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
TUI Tabs Module
|
|
31
|
+
|
|
32
|
+
Individual tab implementations for the HackAgent TUI.
|
|
33
|
+
"""
|