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
hackagent/cli/config.py
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
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
|
+
CLI Configuration Management
|
|
17
|
+
|
|
18
|
+
Handles configuration loading from environment variables, files, and command line arguments.
|
|
19
|
+
Uses standardized priority order: CLI args > Config file > Environment > Default
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
# Sentinel object to detect if a parameter was explicitly passed
|
|
28
|
+
_UNSET = object()
|
|
29
|
+
|
|
30
|
+
# Verbosity level constants (aligned with logging levels)
|
|
31
|
+
VERBOSITY_ERROR = 0 # Only errors
|
|
32
|
+
VERBOSITY_WARNING = 1 # Errors and warnings
|
|
33
|
+
VERBOSITY_INFO = 2 # Errors, warnings, and info
|
|
34
|
+
VERBOSITY_DEBUG = 3 # Everything including debug
|
|
35
|
+
|
|
36
|
+
VERBOSITY_NAMES = {
|
|
37
|
+
0: "ERROR",
|
|
38
|
+
1: "WARNING",
|
|
39
|
+
2: "INFO",
|
|
40
|
+
3: "DEBUG",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
VERBOSITY_LEVELS = {
|
|
44
|
+
"error": 0,
|
|
45
|
+
"warning": 1,
|
|
46
|
+
"info": 2,
|
|
47
|
+
"debug": 3,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CLIConfig:
|
|
52
|
+
"""CLI configuration management with multiple sources"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
api_key=_UNSET,
|
|
57
|
+
base_url=_UNSET,
|
|
58
|
+
config_file=_UNSET,
|
|
59
|
+
verbose=_UNSET,
|
|
60
|
+
output_format=_UNSET,
|
|
61
|
+
):
|
|
62
|
+
"""Initialize with explicit tracking of what was passed via CLI"""
|
|
63
|
+
# Store defaults
|
|
64
|
+
self._defaults = {
|
|
65
|
+
"api_key": None,
|
|
66
|
+
"base_url": "https://api.hackagent.dev",
|
|
67
|
+
"output_format": "table",
|
|
68
|
+
"verbose": VERBOSITY_WARNING, # Default to WARNING level
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Track what was explicitly passed using sentinel values
|
|
72
|
+
self._cli_overrides = set()
|
|
73
|
+
|
|
74
|
+
# Set attributes and track overrides
|
|
75
|
+
# Only mark as CLI override if explicitly provided AND not None
|
|
76
|
+
if api_key is not _UNSET:
|
|
77
|
+
self.api_key = api_key
|
|
78
|
+
# Only treat as CLI override if actually provided (not None from missing env var)
|
|
79
|
+
if api_key is not None:
|
|
80
|
+
self._cli_overrides.add("api_key")
|
|
81
|
+
else:
|
|
82
|
+
self.api_key = self._defaults["api_key"]
|
|
83
|
+
|
|
84
|
+
if base_url is not _UNSET:
|
|
85
|
+
self.base_url = base_url
|
|
86
|
+
# Only treat as CLI override if actually provided (not None from missing env var)
|
|
87
|
+
if base_url is not None:
|
|
88
|
+
self._cli_overrides.add("base_url")
|
|
89
|
+
else:
|
|
90
|
+
self.base_url = self._defaults["base_url"]
|
|
91
|
+
|
|
92
|
+
if config_file is not _UNSET:
|
|
93
|
+
self.config_file = config_file
|
|
94
|
+
# config_file doesn't need to be tracked as an override
|
|
95
|
+
else:
|
|
96
|
+
self.config_file = None
|
|
97
|
+
|
|
98
|
+
if verbose is not _UNSET:
|
|
99
|
+
self.verbose = verbose
|
|
100
|
+
# Only treat as CLI override if actually provided and > 0
|
|
101
|
+
# (Click's count option returns 0 when not specified, so 0 means not set)
|
|
102
|
+
if verbose is not None and verbose > 0:
|
|
103
|
+
self._cli_overrides.add("verbose")
|
|
104
|
+
else:
|
|
105
|
+
self.verbose = self._defaults["verbose"]
|
|
106
|
+
|
|
107
|
+
if output_format is not _UNSET:
|
|
108
|
+
self.output_format = output_format
|
|
109
|
+
# Only treat as CLI override if actually provided (not None from missing env var)
|
|
110
|
+
if output_format is not None:
|
|
111
|
+
self._cli_overrides.add("output_format")
|
|
112
|
+
else:
|
|
113
|
+
self.output_format = self._defaults["output_format"]
|
|
114
|
+
|
|
115
|
+
# STANDARDIZED PRIORITY ORDER:
|
|
116
|
+
# 1. CLI arguments (tracked in _cli_overrides)
|
|
117
|
+
# 2. Config file
|
|
118
|
+
# 3. Environment variables
|
|
119
|
+
# 4. Defaults (already set)
|
|
120
|
+
|
|
121
|
+
# Initialize config overrides tracking
|
|
122
|
+
self._config_overrides = set()
|
|
123
|
+
|
|
124
|
+
if self.config_file:
|
|
125
|
+
self._load_from_file(self.config_file)
|
|
126
|
+
else:
|
|
127
|
+
self._load_default_config()
|
|
128
|
+
|
|
129
|
+
# Load from environment AFTER config file (lower priority)
|
|
130
|
+
self._load_from_env()
|
|
131
|
+
|
|
132
|
+
def _load_from_env(self):
|
|
133
|
+
"""Load from environment variables (only if not already set by CLI or config)"""
|
|
134
|
+
# Only load from env if not explicitly set via CLI args
|
|
135
|
+
# AND (not set by config file OR config file has None value)
|
|
136
|
+
if "api_key" not in self._cli_overrides:
|
|
137
|
+
# Use env if no config override, or if config set None
|
|
138
|
+
if (
|
|
139
|
+
"api_key" not in self._config_overrides
|
|
140
|
+
or getattr(self, "api_key", None) is None
|
|
141
|
+
):
|
|
142
|
+
env_api_key = os.getenv("HACKAGENT_API_KEY")
|
|
143
|
+
if env_api_key:
|
|
144
|
+
self.api_key = env_api_key
|
|
145
|
+
|
|
146
|
+
# Only load output_format from env if not set by CLI or config
|
|
147
|
+
if "output_format" not in self._cli_overrides:
|
|
148
|
+
# Use env if no config override, or if config set None
|
|
149
|
+
if (
|
|
150
|
+
"output_format" not in self._config_overrides
|
|
151
|
+
or getattr(self, "output_format", None) is None
|
|
152
|
+
):
|
|
153
|
+
env_format = os.getenv("HACKAGENT_OUTPUT_FORMAT")
|
|
154
|
+
if env_format:
|
|
155
|
+
self.output_format = env_format
|
|
156
|
+
|
|
157
|
+
def _load_from_file(self, config_path: str):
|
|
158
|
+
"""Load from configuration file (JSON or YAML)"""
|
|
159
|
+
path = Path(config_path)
|
|
160
|
+
if not path.exists():
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
with open(path) as f:
|
|
165
|
+
if path.suffix.lower() in [".yaml", ".yml"]:
|
|
166
|
+
try:
|
|
167
|
+
import yaml
|
|
168
|
+
|
|
169
|
+
config_data = yaml.safe_load(f)
|
|
170
|
+
except ImportError:
|
|
171
|
+
raise ImportError(
|
|
172
|
+
"PyYAML required for YAML config files. Install with: pip install pyyaml"
|
|
173
|
+
)
|
|
174
|
+
else:
|
|
175
|
+
config_data = json.load(f)
|
|
176
|
+
|
|
177
|
+
# STANDARDIZED PRIORITY: CLI args > Config file > Env vars > Defaults
|
|
178
|
+
# Never override CLI arguments, but override defaults and environment will be loaded later
|
|
179
|
+
for key, value in config_data.items():
|
|
180
|
+
# Skip base_url as it's always from CLI/env
|
|
181
|
+
if key == "base_url":
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
# Never override CLI arguments
|
|
185
|
+
if key in self._cli_overrides:
|
|
186
|
+
continue
|
|
187
|
+
|
|
188
|
+
# Set config file values (env will be loaded later for None values)
|
|
189
|
+
if hasattr(self, key):
|
|
190
|
+
setattr(self, key, value)
|
|
191
|
+
# Track that this was set by config file (even if None)
|
|
192
|
+
self._config_overrides.add(key)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
raise ValueError(f"Failed to load config file {config_path}: {e}")
|
|
195
|
+
|
|
196
|
+
def _load_default_config(self):
|
|
197
|
+
"""Load from default config file"""
|
|
198
|
+
default_config = Path.home() / ".hackagent" / "config.json"
|
|
199
|
+
if default_config.exists():
|
|
200
|
+
self._load_from_file(str(default_config))
|
|
201
|
+
|
|
202
|
+
def save(self, path: Optional[str] = None):
|
|
203
|
+
"""Save configuration to file"""
|
|
204
|
+
if not path:
|
|
205
|
+
config_dir = Path.home() / ".hackagent"
|
|
206
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
207
|
+
path = config_dir / "config.json"
|
|
208
|
+
|
|
209
|
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
|
210
|
+
with open(path, "w") as f:
|
|
211
|
+
# Don't save None values or base_url (always hardcoded)
|
|
212
|
+
config_dict = {}
|
|
213
|
+
for attr in ["api_key", "output_format", "verbose"]:
|
|
214
|
+
value = getattr(self, attr, None)
|
|
215
|
+
if value is not None:
|
|
216
|
+
config_dict[attr] = value
|
|
217
|
+
json.dump(config_dict, f, indent=2)
|
|
218
|
+
|
|
219
|
+
def validate(self):
|
|
220
|
+
"""Validate configuration"""
|
|
221
|
+
if not self.api_key:
|
|
222
|
+
raise ValueError(
|
|
223
|
+
"API key is required. Set HACKAGENT_API_KEY environment variable, "
|
|
224
|
+
"use --api-key flag, or run 'hackagent config set --api-key YOUR_KEY'"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if not self.base_url:
|
|
228
|
+
raise ValueError("Base URL is required")
|
|
229
|
+
|
|
230
|
+
def should_show_info(self) -> bool:
|
|
231
|
+
"""Check if INFO level messages should be displayed"""
|
|
232
|
+
return self.verbose >= VERBOSITY_INFO
|
|
233
|
+
|
|
234
|
+
def should_show_warning(self) -> bool:
|
|
235
|
+
"""Check if WARNING level messages should be displayed"""
|
|
236
|
+
return self.verbose >= VERBOSITY_WARNING
|
|
237
|
+
|
|
238
|
+
def should_show_debug(self) -> bool:
|
|
239
|
+
"""Check if DEBUG level messages should be displayed"""
|
|
240
|
+
return self.verbose >= VERBOSITY_DEBUG
|
|
241
|
+
|
|
242
|
+
def get_verbosity_name(self) -> str:
|
|
243
|
+
"""Get the name of the current verbosity level"""
|
|
244
|
+
return VERBOSITY_NAMES.get(self.verbose, "UNKNOWN")
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def default_config_path(self) -> Path:
|
|
248
|
+
"""Get the default configuration file path"""
|
|
249
|
+
return Path.home() / ".hackagent" / "config.json"
|