humanbound-cli 0.1.0__tar.gz → 0.3.0__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.
- {humanbound_cli-0.1.0/humanbound_cli.egg-info → humanbound_cli-0.3.0}/PKG-INFO +86 -27
- humanbound_cli-0.1.0/PKG-INFO → humanbound_cli-0.3.0/README.md +81 -51
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/__init__.py +1 -1
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/client.py +121 -5
- humanbound_cli-0.3.0/humanbound_cli/commands/__init__.py +27 -0
- humanbound_cli-0.3.0/humanbound_cli/commands/api_keys.py +225 -0
- humanbound_cli-0.3.0/humanbound_cli/commands/campaigns.py +174 -0
- humanbound_cli-0.3.0/humanbound_cli/commands/coverage.py +160 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/docs.py +24 -14
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/experiments.py +138 -11
- humanbound_cli-0.3.0/humanbound_cli/commands/findings.py +177 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/init.py +159 -5
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/logs.py +17 -9
- humanbound_cli-0.3.0/humanbound_cli/commands/members.py +179 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/posture.py +73 -1
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/projects.py +96 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/test.py +45 -123
- humanbound_cli-0.3.0/humanbound_cli/commands/upload_logs.py +106 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/config.py +7 -1
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/exceptions.py +18 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/main.py +33 -4
- humanbound_cli-0.3.0/humanbound_cli/report.py +719 -0
- humanbound_cli-0.3.0/humanbound_cli/serve/__init__.py +14 -0
- humanbound_cli-0.3.0/humanbound_cli/serve/config_builder.py +48 -0
- humanbound_cli-0.3.0/humanbound_cli/serve/local_server.py +206 -0
- humanbound_cli-0.3.0/humanbound_cli/serve/runtime_detector.py +421 -0
- humanbound_cli-0.3.0/humanbound_cli/serve/tunnel_client.py +236 -0
- humanbound_cli-0.1.0/README.md → humanbound_cli-0.3.0/humanbound_cli.egg-info/PKG-INFO +110 -24
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli.egg-info/SOURCES.txt +13 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli.egg-info/requires.txt +3 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli.egg-info/top_level.txt +2 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/pyproject.toml +7 -4
- humanbound_cli-0.3.0/relay/relay.py +347 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/tests/cli_integration_test.py +427 -170
- humanbound_cli-0.1.0/humanbound_cli/commands/__init__.py +0 -17
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/LICENSE +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/auth.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/guardrails.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/orgs.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/providers.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/commands/scan.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/extractors/__init__.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/extractors/openapi.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/extractors/repo.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/pytest_plugin/__init__.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/pytest_plugin/fixtures.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli/pytest_plugin/report.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli.egg-info/dependency_links.txt +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/humanbound_cli.egg-info/entry_points.txt +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/setup.cfg +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/tests/__init__.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/tests/conftest.py +0 -0
- {humanbound_cli-0.1.0 → humanbound_cli-0.3.0}/tests/test_cli_commands.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: humanbound-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Humanbound CLI - command line interface for AI agent security testing.
|
|
5
|
-
Author-email: Kostas Siabanis <hello@humanbound.
|
|
5
|
+
Author-email: Kostas Siabanis <hello@humanbound.ai>, Demetris Gerogiannis <hello@humanbound.ai>
|
|
6
6
|
License: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://github.com/Humanbound/humanbound-cli
|
|
8
|
-
Project-URL: Documentation, https://docs.humanbound.
|
|
8
|
+
Project-URL: Documentation, https://docs.humanbound.ai/cli
|
|
9
9
|
Project-URL: Issues, https://github.com/Humanbound/humanbound-cli/issues
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -19,18 +19,21 @@ Requires-Dist: click>=8.1.0
|
|
|
19
19
|
Requires-Dist: rich>=13.0.0
|
|
20
20
|
Requires-Dist: requests>=2.32.0
|
|
21
21
|
Requires-Dist: pyyaml>=6.0.0
|
|
22
|
+
Provides-Extra: serve
|
|
23
|
+
Requires-Dist: websockets>=12.0; extra == "serve"
|
|
22
24
|
Provides-Extra: pytest
|
|
23
25
|
Requires-Dist: pytest>=7.0.0; extra == "pytest"
|
|
24
26
|
Provides-Extra: dev
|
|
25
27
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
26
28
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
27
29
|
|
|
28
|
-
# Humanbound CLI
|
|
30
|
+
# Humanbound CLI
|
|
29
31
|
|
|
30
32
|
> CLI-first security testing for AI agents and chatbots. Adversarial attacks, behavioral QA, posture scoring, and guardrails export — from your terminal to your CI/CD pipeline.
|
|
31
33
|
|
|
32
34
|
[](https://pypi.org/project/humanbound-cli/)
|
|
33
35
|
[]()
|
|
36
|
+
[]()
|
|
34
37
|
|
|
35
38
|
```
|
|
36
39
|
pip install humanbound-cli
|
|
@@ -113,7 +116,7 @@ hb test
|
|
|
113
116
|
hb test -e ./bot-config.json
|
|
114
117
|
|
|
115
118
|
# Choose test category and depth
|
|
116
|
-
hb test -t owasp_multi_turn -l system
|
|
119
|
+
hb test -t humanbound/adversarial/owasp_multi_turn -l system
|
|
117
120
|
```
|
|
118
121
|
|
|
119
122
|
### 4. Review results
|
|
@@ -285,6 +288,8 @@ Providers are LLM configurations used for running security tests.
|
|
|
285
288
|
| `projects use <id>` | Select project |
|
|
286
289
|
| `projects current` | Show current project |
|
|
287
290
|
| `projects show [id]` | Show project details |
|
|
291
|
+
| `projects update [id]` | Update project name/description |
|
|
292
|
+
| `projects delete [id]` | Delete project (with confirmation) |
|
|
288
293
|
|
|
289
294
|
<details>
|
|
290
295
|
<summary><code>init</code> — scan bot & create project</summary>
|
|
@@ -324,27 +329,15 @@ Testing Level:
|
|
|
324
329
|
--testing-level, -l Depth of testing (default: unit)
|
|
325
330
|
unit | system | acceptance
|
|
326
331
|
|
|
327
|
-
|
|
328
|
-
--
|
|
329
|
-
|
|
330
|
-
--chat-payload JSON payload template for chat
|
|
331
|
-
|
|
332
|
-
Init Endpoint (optional):
|
|
333
|
-
--init-endpoint Thread initialization URL
|
|
334
|
-
--init-header Header for init endpoint (repeatable)
|
|
335
|
-
--init-payload JSON payload for init
|
|
336
|
-
|
|
337
|
-
Auth Endpoint (optional):
|
|
338
|
-
--auth-endpoint Auth/token endpoint URL
|
|
339
|
-
--auth-header Header for auth endpoint (repeatable)
|
|
340
|
-
--auth-payload JSON payload for auth
|
|
332
|
+
Endpoint Override (optional — only needed if no default integration):
|
|
333
|
+
-e, --endpoint Bot integration config — JSON string or file path.
|
|
334
|
+
Same shape as 'hb init --endpoint'. Overrides default.
|
|
341
335
|
|
|
342
336
|
Other:
|
|
343
337
|
--provider-id Provider to use (default: first available)
|
|
344
338
|
--name, -n Experiment name (auto-generated if omitted)
|
|
345
339
|
--lang Language (default: english). Accepts codes: en, de, es...
|
|
346
340
|
--adaptive Enable adaptive mode (evolutionary attack strategy)
|
|
347
|
-
--streaming Enable streaming mode (requires wss:// endpoint)
|
|
348
341
|
--no-auto-start Create without starting (manual mode)
|
|
349
342
|
--wait, -w Wait for completion
|
|
350
343
|
--fail-on SEVERITY Exit non-zero if findings >= severity
|
|
@@ -363,7 +356,8 @@ Other:
|
|
|
363
356
|
| `experiments status <id> --watch` | Watch until completion |
|
|
364
357
|
| `experiments wait <id>` | Wait with progressive backoff (30s -> 60s -> 120s -> 300s) |
|
|
365
358
|
| `experiments logs <id>` | List experiment logs |
|
|
366
|
-
| `experiments
|
|
359
|
+
| `experiments terminate <id>` | Stop a running experiment |
|
|
360
|
+
| `experiments delete <id>` | Delete experiment (with confirmation) |
|
|
367
361
|
|
|
368
362
|
`status` is also available as a top-level alias — without an ID it shows the most recent experiment:
|
|
369
363
|
|
|
@@ -371,14 +365,79 @@ Other:
|
|
|
371
365
|
hb status [experiment_id] [--watch]
|
|
372
366
|
```
|
|
373
367
|
|
|
368
|
+
### Findings
|
|
369
|
+
|
|
370
|
+
Track long-term security vulnerabilities across experiments.
|
|
371
|
+
|
|
372
|
+
| Command | Description |
|
|
373
|
+
|---------|-------------|
|
|
374
|
+
| `findings` | List findings (filterable by --status, --severity) |
|
|
375
|
+
| `findings update <id>` | Update finding status or severity |
|
|
376
|
+
|
|
377
|
+
Finding states: **open** → **stale** (30+ days unseen) → **fixed** (resolved). Findings can also **regress** (was fixed, reappeared).
|
|
378
|
+
|
|
379
|
+
### Coverage
|
|
380
|
+
|
|
381
|
+
| Command | Description |
|
|
382
|
+
|---------|-------------|
|
|
383
|
+
| `coverage` | Test coverage summary |
|
|
384
|
+
| `coverage --gaps` | Include untested categories |
|
|
385
|
+
|
|
386
|
+
### Campaigns
|
|
387
|
+
|
|
388
|
+
Continuous security assurance with automated campaign management (ASCAM).
|
|
389
|
+
|
|
390
|
+
| Command | Description |
|
|
391
|
+
|---------|-------------|
|
|
392
|
+
| `campaigns` | Show current campaign plan |
|
|
393
|
+
| `campaigns break` | Stop a running campaign |
|
|
394
|
+
|
|
395
|
+
ASCAM phases: Reconnaissance → Hardening → Red Teaming → Analysis → Monitoring
|
|
396
|
+
|
|
397
|
+
### Upload Conversation Logs
|
|
398
|
+
|
|
399
|
+
Evaluate real production conversations against security judges.
|
|
400
|
+
|
|
401
|
+
| Command | Description |
|
|
402
|
+
|---------|-------------|
|
|
403
|
+
| `upload-logs <file>` | Upload JSON conversation logs |
|
|
404
|
+
|
|
405
|
+
Options: `--tag`, `--lang`
|
|
406
|
+
|
|
407
|
+
### API Keys
|
|
408
|
+
|
|
409
|
+
| Command | Description |
|
|
410
|
+
|---------|-------------|
|
|
411
|
+
| `api-keys list` | List API keys |
|
|
412
|
+
| `api-keys create` | Create new key (--name required, --scopes: admin/write/read) |
|
|
413
|
+
| `api-keys update <id>` | Update key name, scopes, or active state |
|
|
414
|
+
| `api-keys revoke <id>` | Revoke (delete) an API key |
|
|
415
|
+
|
|
416
|
+
### Members
|
|
417
|
+
|
|
418
|
+
| Command | Description |
|
|
419
|
+
|---------|-------------|
|
|
420
|
+
| `members list` | List organisation members |
|
|
421
|
+
| `members invite <email>` | Invite member (--role: admin/developer) |
|
|
422
|
+
| `members remove <id>` | Remove member |
|
|
423
|
+
|
|
374
424
|
### Results & Export
|
|
375
425
|
|
|
376
426
|
```bash
|
|
377
|
-
# View experiment results
|
|
378
|
-
hb logs [experiment_id] [--format table] [--verdict pass|fail] [--page N] [--size N]
|
|
427
|
+
# View experiment results
|
|
428
|
+
hb logs [experiment_id] [--format table|json|html] [--verdict pass|fail] [--page N] [--size N]
|
|
429
|
+
|
|
430
|
+
# Export branded HTML report
|
|
431
|
+
hb logs <experiment_id> --format=html [-o report.html]
|
|
432
|
+
|
|
433
|
+
# Security posture
|
|
434
|
+
hb posture [--json] [--trends]
|
|
435
|
+
|
|
436
|
+
# Test coverage
|
|
437
|
+
hb coverage [--gaps] [--json]
|
|
379
438
|
|
|
380
|
-
#
|
|
381
|
-
hb
|
|
439
|
+
# Findings
|
|
440
|
+
hb findings [--status open] [--severity high] [--json]
|
|
382
441
|
|
|
383
442
|
# Export guardrails configuration
|
|
384
443
|
hb guardrails [--vendor humanbound|openai] [--format json|yaml] [-o FILE]
|
|
@@ -406,7 +465,7 @@ hb switch abc123
|
|
|
406
465
|
hb init -n "Support Bot" -e ./bot-config.json
|
|
407
466
|
|
|
408
467
|
# Run adversarial test (uses project's default integration)
|
|
409
|
-
hb test -t owasp_multi_turn -l unit
|
|
468
|
+
hb test -t humanbound/adversarial/owasp_multi_turn -l unit
|
|
410
469
|
|
|
411
470
|
# Watch and review
|
|
412
471
|
hb status --watch
|
|
@@ -494,5 +553,5 @@ hb login
|
|
|
494
553
|
|
|
495
554
|
## Links
|
|
496
555
|
|
|
497
|
-
- [Documentation](https://docs.humanbound.
|
|
556
|
+
- [Documentation](https://docs.humanbound.ai)
|
|
498
557
|
- [GitHub](https://github.com/Humanbound/humanbound-cli)
|
|
@@ -1,36 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
Name: humanbound-cli
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Humanbound CLI - command line interface for AI agent security testing.
|
|
5
|
-
Author-email: Kostas Siabanis <hello@humanbound.io>, Demetris Gerogiannis <hello@humanbound.io>
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/Humanbound/humanbound-cli
|
|
8
|
-
Project-URL: Documentation, https://docs.humanbound.io/cli
|
|
9
|
-
Project-URL: Issues, https://github.com/Humanbound/humanbound-cli/issues
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Framework :: Pytest
|
|
15
|
-
Requires-Python: >=3.10
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
License-File: LICENSE
|
|
18
|
-
Requires-Dist: click>=8.1.0
|
|
19
|
-
Requires-Dist: rich>=13.0.0
|
|
20
|
-
Requires-Dist: requests>=2.32.0
|
|
21
|
-
Requires-Dist: pyyaml>=6.0.0
|
|
22
|
-
Provides-Extra: pytest
|
|
23
|
-
Requires-Dist: pytest>=7.0.0; extra == "pytest"
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
26
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
27
|
-
|
|
28
|
-
# Humanbound CLI (Beta)
|
|
1
|
+
# Humanbound CLI
|
|
29
2
|
|
|
30
3
|
> CLI-first security testing for AI agents and chatbots. Adversarial attacks, behavioral QA, posture scoring, and guardrails export — from your terminal to your CI/CD pipeline.
|
|
31
4
|
|
|
32
5
|
[](https://pypi.org/project/humanbound-cli/)
|
|
33
6
|
[]()
|
|
7
|
+
[]()
|
|
34
8
|
|
|
35
9
|
```
|
|
36
10
|
pip install humanbound-cli
|
|
@@ -113,7 +87,7 @@ hb test
|
|
|
113
87
|
hb test -e ./bot-config.json
|
|
114
88
|
|
|
115
89
|
# Choose test category and depth
|
|
116
|
-
hb test -t owasp_multi_turn -l system
|
|
90
|
+
hb test -t humanbound/adversarial/owasp_multi_turn -l system
|
|
117
91
|
```
|
|
118
92
|
|
|
119
93
|
### 4. Review results
|
|
@@ -285,6 +259,8 @@ Providers are LLM configurations used for running security tests.
|
|
|
285
259
|
| `projects use <id>` | Select project |
|
|
286
260
|
| `projects current` | Show current project |
|
|
287
261
|
| `projects show [id]` | Show project details |
|
|
262
|
+
| `projects update [id]` | Update project name/description |
|
|
263
|
+
| `projects delete [id]` | Delete project (with confirmation) |
|
|
288
264
|
|
|
289
265
|
<details>
|
|
290
266
|
<summary><code>init</code> — scan bot & create project</summary>
|
|
@@ -324,27 +300,15 @@ Testing Level:
|
|
|
324
300
|
--testing-level, -l Depth of testing (default: unit)
|
|
325
301
|
unit | system | acceptance
|
|
326
302
|
|
|
327
|
-
|
|
328
|
-
--
|
|
329
|
-
|
|
330
|
-
--chat-payload JSON payload template for chat
|
|
331
|
-
|
|
332
|
-
Init Endpoint (optional):
|
|
333
|
-
--init-endpoint Thread initialization URL
|
|
334
|
-
--init-header Header for init endpoint (repeatable)
|
|
335
|
-
--init-payload JSON payload for init
|
|
336
|
-
|
|
337
|
-
Auth Endpoint (optional):
|
|
338
|
-
--auth-endpoint Auth/token endpoint URL
|
|
339
|
-
--auth-header Header for auth endpoint (repeatable)
|
|
340
|
-
--auth-payload JSON payload for auth
|
|
303
|
+
Endpoint Override (optional — only needed if no default integration):
|
|
304
|
+
-e, --endpoint Bot integration config — JSON string or file path.
|
|
305
|
+
Same shape as 'hb init --endpoint'. Overrides default.
|
|
341
306
|
|
|
342
307
|
Other:
|
|
343
308
|
--provider-id Provider to use (default: first available)
|
|
344
309
|
--name, -n Experiment name (auto-generated if omitted)
|
|
345
310
|
--lang Language (default: english). Accepts codes: en, de, es...
|
|
346
311
|
--adaptive Enable adaptive mode (evolutionary attack strategy)
|
|
347
|
-
--streaming Enable streaming mode (requires wss:// endpoint)
|
|
348
312
|
--no-auto-start Create without starting (manual mode)
|
|
349
313
|
--wait, -w Wait for completion
|
|
350
314
|
--fail-on SEVERITY Exit non-zero if findings >= severity
|
|
@@ -363,7 +327,8 @@ Other:
|
|
|
363
327
|
| `experiments status <id> --watch` | Watch until completion |
|
|
364
328
|
| `experiments wait <id>` | Wait with progressive backoff (30s -> 60s -> 120s -> 300s) |
|
|
365
329
|
| `experiments logs <id>` | List experiment logs |
|
|
366
|
-
| `experiments
|
|
330
|
+
| `experiments terminate <id>` | Stop a running experiment |
|
|
331
|
+
| `experiments delete <id>` | Delete experiment (with confirmation) |
|
|
367
332
|
|
|
368
333
|
`status` is also available as a top-level alias — without an ID it shows the most recent experiment:
|
|
369
334
|
|
|
@@ -371,14 +336,79 @@ Other:
|
|
|
371
336
|
hb status [experiment_id] [--watch]
|
|
372
337
|
```
|
|
373
338
|
|
|
339
|
+
### Findings
|
|
340
|
+
|
|
341
|
+
Track long-term security vulnerabilities across experiments.
|
|
342
|
+
|
|
343
|
+
| Command | Description |
|
|
344
|
+
|---------|-------------|
|
|
345
|
+
| `findings` | List findings (filterable by --status, --severity) |
|
|
346
|
+
| `findings update <id>` | Update finding status or severity |
|
|
347
|
+
|
|
348
|
+
Finding states: **open** → **stale** (30+ days unseen) → **fixed** (resolved). Findings can also **regress** (was fixed, reappeared).
|
|
349
|
+
|
|
350
|
+
### Coverage
|
|
351
|
+
|
|
352
|
+
| Command | Description |
|
|
353
|
+
|---------|-------------|
|
|
354
|
+
| `coverage` | Test coverage summary |
|
|
355
|
+
| `coverage --gaps` | Include untested categories |
|
|
356
|
+
|
|
357
|
+
### Campaigns
|
|
358
|
+
|
|
359
|
+
Continuous security assurance with automated campaign management (ASCAM).
|
|
360
|
+
|
|
361
|
+
| Command | Description |
|
|
362
|
+
|---------|-------------|
|
|
363
|
+
| `campaigns` | Show current campaign plan |
|
|
364
|
+
| `campaigns break` | Stop a running campaign |
|
|
365
|
+
|
|
366
|
+
ASCAM phases: Reconnaissance → Hardening → Red Teaming → Analysis → Monitoring
|
|
367
|
+
|
|
368
|
+
### Upload Conversation Logs
|
|
369
|
+
|
|
370
|
+
Evaluate real production conversations against security judges.
|
|
371
|
+
|
|
372
|
+
| Command | Description |
|
|
373
|
+
|---------|-------------|
|
|
374
|
+
| `upload-logs <file>` | Upload JSON conversation logs |
|
|
375
|
+
|
|
376
|
+
Options: `--tag`, `--lang`
|
|
377
|
+
|
|
378
|
+
### API Keys
|
|
379
|
+
|
|
380
|
+
| Command | Description |
|
|
381
|
+
|---------|-------------|
|
|
382
|
+
| `api-keys list` | List API keys |
|
|
383
|
+
| `api-keys create` | Create new key (--name required, --scopes: admin/write/read) |
|
|
384
|
+
| `api-keys update <id>` | Update key name, scopes, or active state |
|
|
385
|
+
| `api-keys revoke <id>` | Revoke (delete) an API key |
|
|
386
|
+
|
|
387
|
+
### Members
|
|
388
|
+
|
|
389
|
+
| Command | Description |
|
|
390
|
+
|---------|-------------|
|
|
391
|
+
| `members list` | List organisation members |
|
|
392
|
+
| `members invite <email>` | Invite member (--role: admin/developer) |
|
|
393
|
+
| `members remove <id>` | Remove member |
|
|
394
|
+
|
|
374
395
|
### Results & Export
|
|
375
396
|
|
|
376
397
|
```bash
|
|
377
|
-
# View experiment results
|
|
378
|
-
hb logs [experiment_id] [--format table] [--verdict pass|fail] [--page N] [--size N]
|
|
398
|
+
# View experiment results
|
|
399
|
+
hb logs [experiment_id] [--format table|json|html] [--verdict pass|fail] [--page N] [--size N]
|
|
400
|
+
|
|
401
|
+
# Export branded HTML report
|
|
402
|
+
hb logs <experiment_id> --format=html [-o report.html]
|
|
403
|
+
|
|
404
|
+
# Security posture
|
|
405
|
+
hb posture [--json] [--trends]
|
|
406
|
+
|
|
407
|
+
# Test coverage
|
|
408
|
+
hb coverage [--gaps] [--json]
|
|
379
409
|
|
|
380
|
-
#
|
|
381
|
-
hb
|
|
410
|
+
# Findings
|
|
411
|
+
hb findings [--status open] [--severity high] [--json]
|
|
382
412
|
|
|
383
413
|
# Export guardrails configuration
|
|
384
414
|
hb guardrails [--vendor humanbound|openai] [--format json|yaml] [-o FILE]
|
|
@@ -406,7 +436,7 @@ hb switch abc123
|
|
|
406
436
|
hb init -n "Support Bot" -e ./bot-config.json
|
|
407
437
|
|
|
408
438
|
# Run adversarial test (uses project's default integration)
|
|
409
|
-
hb test -t owasp_multi_turn -l unit
|
|
439
|
+
hb test -t humanbound/adversarial/owasp_multi_turn -l unit
|
|
410
440
|
|
|
411
441
|
# Watch and review
|
|
412
442
|
hb status --watch
|
|
@@ -494,5 +524,5 @@ hb login
|
|
|
494
524
|
|
|
495
525
|
## Links
|
|
496
526
|
|
|
497
|
-
- [Documentation](https://docs.humanbound.
|
|
527
|
+
- [Documentation](https://docs.humanbound.ai)
|
|
498
528
|
- [GitHub](https://github.com/Humanbound/humanbound-cli)
|
|
@@ -387,12 +387,9 @@ class HumanboundClient:
|
|
|
387
387
|
return True
|
|
388
388
|
|
|
389
389
|
def _exchange_for_api_token(self) -> None:
|
|
390
|
-
"""Exchange Auth0 token for
|
|
391
|
-
# Always use production API for auth (token audience must match)
|
|
392
|
-
auth_base_url = get_auth0_audience()
|
|
393
|
-
|
|
390
|
+
"""Exchange Auth0 token for API session token."""
|
|
394
391
|
response = requests.get(
|
|
395
|
-
f"{
|
|
392
|
+
f"{self.base_url}/auth",
|
|
396
393
|
headers={"Authorization": f"Bearer {self._auth0_token}"},
|
|
397
394
|
timeout=DEFAULT_TIMEOUT,
|
|
398
395
|
)
|
|
@@ -870,6 +867,125 @@ class HumanboundClient:
|
|
|
870
867
|
"""
|
|
871
868
|
self.delete(f"providers/{provider_id}")
|
|
872
869
|
|
|
870
|
+
# -------------------------------------------------------------------------
|
|
871
|
+
# Findings Methods
|
|
872
|
+
# -------------------------------------------------------------------------
|
|
873
|
+
|
|
874
|
+
def list_findings(self, project_id: str, status: Optional[str] = None, severity: Optional[str] = None, page: int = 1, size: int = 50) -> dict:
|
|
875
|
+
"""List findings for a project."""
|
|
876
|
+
params = {"page": page, "size": size}
|
|
877
|
+
if status:
|
|
878
|
+
params["status"] = status
|
|
879
|
+
if severity:
|
|
880
|
+
params["severity"] = severity
|
|
881
|
+
return self.get(f"projects/{project_id}/findings", include_project=True, params=params)
|
|
882
|
+
|
|
883
|
+
def update_finding(self, project_id: str, finding_id: str, data: dict) -> dict:
|
|
884
|
+
"""Update a finding."""
|
|
885
|
+
return self.put(f"projects/{project_id}/findings/{finding_id}", data=data)
|
|
886
|
+
|
|
887
|
+
# -------------------------------------------------------------------------
|
|
888
|
+
# Experiment Extensions
|
|
889
|
+
# -------------------------------------------------------------------------
|
|
890
|
+
|
|
891
|
+
def terminate_experiment(self, experiment_id: str) -> dict:
|
|
892
|
+
"""Terminate a running experiment."""
|
|
893
|
+
return self.post(f"experiments/{experiment_id}/terminate", include_project=True)
|
|
894
|
+
|
|
895
|
+
def delete_experiment(self, experiment_id: str) -> Any:
|
|
896
|
+
"""Delete an experiment."""
|
|
897
|
+
return self.delete(f"experiments/{experiment_id}", include_project=True)
|
|
898
|
+
|
|
899
|
+
# -------------------------------------------------------------------------
|
|
900
|
+
# Project Extensions
|
|
901
|
+
# -------------------------------------------------------------------------
|
|
902
|
+
|
|
903
|
+
def update_project(self, project_id: str, data: dict) -> dict:
|
|
904
|
+
"""Update a project."""
|
|
905
|
+
return self.put(f"projects/{project_id}", data=data)
|
|
906
|
+
|
|
907
|
+
def delete_project(self, project_id: str) -> Any:
|
|
908
|
+
"""Delete a project."""
|
|
909
|
+
return self.delete(f"projects/{project_id}")
|
|
910
|
+
|
|
911
|
+
# -------------------------------------------------------------------------
|
|
912
|
+
# API Key Methods
|
|
913
|
+
# -------------------------------------------------------------------------
|
|
914
|
+
|
|
915
|
+
def list_api_keys(self, page: int = 1, limit: int = 50) -> Any:
|
|
916
|
+
"""List API keys."""
|
|
917
|
+
return self.get("api-keys", params={"page": page, "limit": limit}, include_org=False)
|
|
918
|
+
|
|
919
|
+
def create_api_key(self, name: str, scopes: str = "admin") -> dict:
|
|
920
|
+
"""Create a new API key."""
|
|
921
|
+
return self.post("api-keys", data={"name": name, "scopes": scopes}, include_org=False)
|
|
922
|
+
|
|
923
|
+
def delete_api_key(self, key_id: str) -> Any:
|
|
924
|
+
"""Delete an API key."""
|
|
925
|
+
return self.delete(f"api-keys/{key_id}", include_org=False)
|
|
926
|
+
|
|
927
|
+
def update_api_key(self, key_id: str, data: dict) -> dict:
|
|
928
|
+
"""Update an API key."""
|
|
929
|
+
return self.put(f"api-keys/{key_id}", data=data, include_org=False)
|
|
930
|
+
|
|
931
|
+
# -------------------------------------------------------------------------
|
|
932
|
+
# Member Methods
|
|
933
|
+
# -------------------------------------------------------------------------
|
|
934
|
+
|
|
935
|
+
def list_members(self) -> Any:
|
|
936
|
+
"""List organisation members."""
|
|
937
|
+
return self.get("members")
|
|
938
|
+
|
|
939
|
+
def invite_member(self, email: str, access_level: str) -> dict:
|
|
940
|
+
"""Invite a member to the organisation."""
|
|
941
|
+
return self.post("members", data={"email": email, "access_level": access_level})
|
|
942
|
+
|
|
943
|
+
def remove_member(self, member_id: str) -> Any:
|
|
944
|
+
"""Remove a member from the organisation."""
|
|
945
|
+
return self.delete(f"members/{member_id}")
|
|
946
|
+
|
|
947
|
+
# -------------------------------------------------------------------------
|
|
948
|
+
# Coverage Methods
|
|
949
|
+
# -------------------------------------------------------------------------
|
|
950
|
+
|
|
951
|
+
def get_coverage(self, project_id: str, include_gaps: bool = False) -> dict:
|
|
952
|
+
"""Get test coverage for a project."""
|
|
953
|
+
params = {"include_gaps": "true"} if include_gaps else {}
|
|
954
|
+
return self.get(f"projects/{project_id}/coverage", params=params)
|
|
955
|
+
|
|
956
|
+
# -------------------------------------------------------------------------
|
|
957
|
+
# Posture Trends Methods
|
|
958
|
+
# -------------------------------------------------------------------------
|
|
959
|
+
|
|
960
|
+
def get_posture_trends(self, project_id: str) -> Any:
|
|
961
|
+
"""Get posture trend history for a project."""
|
|
962
|
+
return self.get(f"projects/{project_id}/posture/trends")
|
|
963
|
+
|
|
964
|
+
# -------------------------------------------------------------------------
|
|
965
|
+
# Campaign Methods
|
|
966
|
+
# -------------------------------------------------------------------------
|
|
967
|
+
|
|
968
|
+
def get_campaign_plan(self, project_id: str) -> dict:
|
|
969
|
+
"""Get the current campaign plan for a project."""
|
|
970
|
+
return self.get(f"projects/{project_id}/plan")
|
|
971
|
+
|
|
972
|
+
def break_campaign(self, project_id: str, campaign_id: str) -> dict:
|
|
973
|
+
"""Break/stop a running campaign."""
|
|
974
|
+
return self.post(f"projects/{project_id}/plan/break", data={"campaign_id": campaign_id})
|
|
975
|
+
|
|
976
|
+
# -------------------------------------------------------------------------
|
|
977
|
+
# Upload Conversations Methods
|
|
978
|
+
# -------------------------------------------------------------------------
|
|
979
|
+
|
|
980
|
+
def upload_conversations(self, project_id: str, conversations: list, tag: Optional[str] = None, lang: Optional[str] = None) -> dict:
|
|
981
|
+
"""Upload conversation logs for evaluation."""
|
|
982
|
+
data = {"conversations": conversations}
|
|
983
|
+
if tag:
|
|
984
|
+
data["tag"] = tag
|
|
985
|
+
if lang:
|
|
986
|
+
data["lang"] = lang
|
|
987
|
+
return self.post(f"projects/{project_id}/datasets/conversations", data=data, include_project=True)
|
|
988
|
+
|
|
873
989
|
|
|
874
990
|
# Import ValidationError to this module
|
|
875
991
|
from .exceptions import ValidationError
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""CLI command modules."""
|
|
2
|
+
|
|
3
|
+
from . import (
|
|
4
|
+
auth, orgs, projects, experiments, init, test, logs, posture,
|
|
5
|
+
guardrails, docs, providers, findings, api_keys, members,
|
|
6
|
+
coverage, campaigns, upload_logs,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"auth",
|
|
11
|
+
"orgs",
|
|
12
|
+
"projects",
|
|
13
|
+
"experiments",
|
|
14
|
+
"init",
|
|
15
|
+
"test",
|
|
16
|
+
"logs",
|
|
17
|
+
"posture",
|
|
18
|
+
"guardrails",
|
|
19
|
+
"docs",
|
|
20
|
+
"providers",
|
|
21
|
+
"findings",
|
|
22
|
+
"api_keys",
|
|
23
|
+
"members",
|
|
24
|
+
"coverage",
|
|
25
|
+
"campaigns",
|
|
26
|
+
"upload_logs",
|
|
27
|
+
]
|