deepcyber-ai/airt-harness
GitHub: deepcyber-ai/airt-harness
一个通用的AI红队测试框架,通过协议转换和统一接口连接各类红队工具与目标AI系统。
Stars: 0 | Forks: 0
# DeepCyber AI 红队测试框架
一个用于 AI 红队测试的通用测试框架。它位于您的红队工具和目标 AI 系统之间,提供统一的规范 API、协议转换、模拟仿真、情报收集和回归重放。
```
____ ______ __
/ __ \___ ___ ____ / ____/_ __/ /_ ___ _____
/ / / / _ \/ _ \/ __ \/ / / / / / __ \/ _ \/ ___/
/ /_/ / __/ __/ /_/ / /___/ /_/ / /_/ / __/ /
/_____/\___/\___/ .___/\____/\__, /_.___/\___/_/
/_/ /____/
AI Red Teaming Harness
```
```
pip install airt-harness
```
**一套框架,任意目标,任意工具。** 只需为目标的有线格式编写一次映射器,然后每一个红队工具——PyRIT、Promptfoo、Garak、Spikee、curl 或您自己的脚本——都可以与同一个规范 API 通信。在无需修改工具的情况下,即可在真实目标和本地模拟器之间切换。在修复后重放记录的漏洞会话,以进行回归测试。
### 核心能力
- **统一 API** —— 在任意目标前提供规范的 OpenAI 兼容 `/v1/chat/completions` 端点,无论其原生有线格式如何
- **协议转换** —— 双向消息映射器按目标处理身份验证、标头、会话管理和响应解析
- **模拟仿真** —— 本地模拟服务器,具有可插拔的 LLM 后端(Ollama、OpenAI、Anthropic、Gemini、DeepSeek、echo),使用目标的确切有线格式
- **情报收集** —— 将每个请求/响应记录为 JSONL,以便分析和重放
- **回归重放** —— 从情报日志或精选的 Metabase CSV 重放记录的攻击会话,比较响应,并使用 LLM 评判器进行评分
- **配置隔离** —— 每次演练的配置文件独立保存配置、日志和情报
## 架构
```
Red Team Tool / curl / Promptfoo / Replay
|
v
HARNESS (server.py)
- Canonical /v1/chat/completions endpoint (OpenAI-compatible)
- Simplified /chat endpoint
- Auth, retry, token refresh, intel collection
|
v
MESSAGE MAPPER (mappers/example.py, your_target.py, ...)
- Canonical <-> target wire format translation
- Bidirectional: client side + mock server side
|
v
TARGET (real API or mock server)
- Real: mTLS, bearer, API key -- whatever the target needs
- Mock: local LLM (ollama, openai, anthropic, gemini, deepseek, echo)
```
## 快速开始
该框架附带一个默认配置文件(**Deep Vault Capital**,一家虚构的英国金融公司),因此您可以立即开始,而无需任何配置、API 密钥或证书。
```
# 安装
pip install airt-harness
# 启动 harness 容器(echo 后端,无需 API 密钥)
MOCK_BACKEND=echo airt-launch
# 测试
curl http://localhost:8000/health
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"input": "What is an ISA?"}'
# 重放录制的会话以进行回归测试
airt-replay profiles/default/intel/ --list-sessions
airt-replay profiles/default/intel/ --session
# 停止
airt-stop
```
### 从源码(不使用 Docker)
```
pip install -r requirements.txt
# 使用默认配置文件启动 mock 服务器
python -m harness.mock --backend echo --port 8089
# 启动指向 mock 的 harness
BACKEND=mock uvicorn harness.server:app --port 8000
# 测试
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"input": "What is an ISA?"}'
```
## Docker
```
docker build -t deepcyber/airt-harness .
docker run -p 7860:7860 -p 8000:8000 -p 8089:8089 deepcyber/airt-harness
# 使用从镜像外部挂载的自定义配置文件:
docker run -p 8000:8000 \
-v ./profiles/myproject:/app/profiles/myproject \
-e PROFILE=profiles/myproject/profile.yaml \
deepcyber/airt-harness
```
## 端点
| Endpoint | Method | Purpose |
|---|---|---|
| `/v1/chat/completions` | POST | 规范的 OpenAI 兼容(与任何 OpenAI 兼容工具一起使用) |
| `/chat` | POST | 简化版:`{"input": "message"}` + 可选的 `x-session-id` 标头 |
| `/auth` | POST | 验证/刷新身份验证(mTLS 证书检查或令牌刷新) |
| `/firewall` | POST | 开启/关闭 HB Firewall(默认关闭) |
| `/init` | POST | 初始化会话(对于需要显式初始化的目标) |
| `/backend` | POST | 在运行时在真实后端和模拟后端之间切换 |
| `/token` | POST | 无需重启即可热交换 bearer token |
| `/health` | GET | 当前配置和状态 |
| `/intel/summary` | GET | 记录的 API 调用摘要 |
| `/v1/models` | GET | OpenAI 兼容的模型列表 |
## 切换配置文件
### 启动时(环境变量)
```
# 默认(Deep Vault Capital -- 无需配置)
uvicorn harness.server:app --port 8000
# 你的 engagement 配置文件
PROFILE=profiles/myproject/profile.yaml uvicorn harness.server:app --port 8000
```
模拟服务器使用相同的 `--profile` 标志:
```
python -m harness.mock --profile profiles/myproject/profile.yaml --backend echo
```
### 运行时(后端切换)
在无需重启的情况下在真实目标和模拟器之间切换:
```
# 切换到 mock
curl -X POST http://localhost:8000/backend -d '{"backend": "mock"}'
# 切换到真实目标
curl -X POST http://localhost:8000/backend -d '{"backend": "real"}'
# 切换(无 body)
curl -X POST http://localhost:8000/backend
```
后端状态在重启后持久保存(保存到配置文件目录中的 `.harness_state.json`)。
## 日志隔离
每个配置文件的数据都存储在其自己的目录中——不同的配置文件绝不会相互污染:
```
profiles/
myproject/
harness.log # Harness server log (this profile only)
mock_server.log # Mock server log (this profile only)
mock-audit.jsonl # Mock audit trail (this profile only)
intel/
responses.jsonl # Intel store (this profile only)
.harness_state.json # Backend state (this profile only)
```
如果需要,您可以在 `profile.yaml` 中覆盖日志和情报路径:
```
harness:
intel_dir: /custom/path/intel
log_file: /custom/path/harness.log
```
但建议使用默认值(配置文件目录)以保持隔离。
## 项目配置文件
每次演练都会获得一个配置文件目录:
```
profiles/
myproject/
profile.yaml # Target config (API, auth, TLS, session, mock)
mock/
system_prompt.txt # Optional custom system prompt for the mock server
certs/ # TLS client certificates (gitignored)
```
### 配置文件 YAML
```
target: example # mapper name (built-in or custom)
display_name: "My Target" # shown in GUI and health endpoint
# 对于位于此包之外的 engagement 专用 mapper:
# target_module: profiles.myproject.mapper
api:
url: "https://api.example.com"
path: "/v1/chat"
auth:
mode: none # none | bearer | api_key
bearer:
env_var: MY_BEARER_TOKEN
prefix: "Bearer "
token_refresh:
order: ["cli"] # ["cli"] | ["endpoint"] | ["cli", "endpoint"]
cli:
command: "gcloud auth print-access-token"
endpoint:
url: "" # remote token server URL
secret_env: TOKEN_SECRET
tls:
cert: certs/tls.crt
key: certs/tls.key
ca_bundle: null # null = no verify; path = custom CA
verify: false # true = system CA store
session:
header: x-session-id # header for session ID
prefix: "replay-"
mock:
url: "http://localhost:8089"
harness:
port: 8000
# intel_dir and log_file default to the profile directory
```
## 消息映射器
映射器在框架的规范格式和目标的有线协议之间进行转换。每个映射器都是双向的:
| Method | Side | Purpose |
|---|---|---|
| `build_request(message, session_id)` | Client | 规范 -> 目标请求 |
| `parse_response(data)` | Client | 目标响应 -> 规范格式 |
| `parse_incoming_request(body, headers)` | Server | 目标请求 -> 提取消息(用于模拟) |
| `build_mock_response(answer, session_id)` | Server | LLM 应答 -> 目标响应格式(用于模拟) |
该框架附带一个内置映射器作为起点:
| Mapper | Wire format | Use case |
|---|---|---|
| `example` | 扁平化 JSON `{"input": "..."}` 请求,`{"output": "...", "session_id": "..."}` 响应,会话 ID 在 `x-session-id` 标头中 | 通用基线;复制并改编 |
### 添加新的映射器
两种方式:
**1. 作为内置映射器(适合您想要发布的映射器):**
1. 将 `harness/mappers/example.py` 复制到 `harness/mappers/mytarget.py`
2. 继承 `BaseMapper`,实现四个方法,设置 `name = "mytarget"`
3. 在 `mappers/__init__.py` 的 `_BUILTIN_MAPPERS` 中添加 `"mytarget": "harness.mappers.mytarget"`
4. 在您的配置文件中:`target: mytarget`
**2. 作为演练专用的私有映射器(保留在此仓库之外):**
1. 创建一个带有 `create_mapper(config)` 函数的 `profiles/myproject/mapper.py`
2. 在您的配置文件 YAML 中,将 `target_module:` 指向可导入模块或文件路径:
target: myproject # 显示/日志记录名称
target_module: profiles/myproject/mapper.py # 文件路径(相对于 CWD)
# 或者:
# target_module: my_package.my_target_mapper # 可导入模块
3. 从文件或模块可访问的目录运行框架
这使您可以将特定于客户的映射器保留在私有仓库中,同时共享来自此仓库的框架脚手架。
### 通用映射器(仅限 YAML,无需 Python)
对于具有标准 REST API 的目标,请使用内置的 `generic` 映射器,而不是编写自定义映射器文件。完全在 profile.yaml 中配置请求正文模板和响应提取路径:
```
target: generic
api:
url: "https://api.example.com"
path: "/v1/chat"
# 请求体 —— {{PROMPT}} 替换为用户消息
request_template:
model: "gpt-4"
messages:
- role: "user"
content: "{{PROMPT}}"
# 用于从 JSON 响应中提取答案的点记法路径
response_path: "choices.0.message.content"
```
点表示法示例:
| Target response shape | `response_path` |
|---|---|
| `{"answer": "..."}` | `answer` |
| `{"responses": [{"value": "..."}]}` | `responses.0.value` |
| `{"choices": [{"message": {"content": "..."}}]}` | `choices.0.message.content` |
对于具有复杂有线格式(SSE、双重编码、自定义会话初始化)的目标,请改用自定义映射器。
## PyRIT 集成
该框架提供兼容 PyRIT 的目标,用于自动化的红队测试编排。
```
pip install airt-harness[pyrit]
```
### ProxyTarget —— 通过框架路由
```
from harness.pyrit import ProxyTarget
target = ProxyTarget(
harness_url="http://localhost:8000",
session_id="RedTeam-001",
)
# 与任何 PyRIT orchestrator 配合使用
from pyrit.orchestrator import PromptSendingOrchestrator
orchestrator = PromptSendingOrchestrator(objective_target=target)
```
`ProxyTarget` 将提示发送到框架 `/chat` 端点。该框架处理协议转换、身份验证、会话管理和情报收集——PyRIT 只看到一个简单的文本输入/文本输出目标。
### BedrockTarget —— 直接连接 AWS Bedrock
```
from harness.pyrit import BedrockTarget
target = BedrockTarget(
model_id="anthropic.claude-sonnet-4-6",
region="eu-west-2",
)
```
需要 `pip install airt-harness[bedrock]` 并配置 AWS 凭证。
## HB Firewall
使用 HumanBound Firewall 的可选输入筛选层。**默认关闭。** 启用后,每条消息在到达目标之前都会被评估——被阻止的消息将收到标准的拒绝响应。
### 运行时启用
```
# 启用
curl -X POST http://localhost:8000/firewall -d '{"enabled": true}'
# 禁用
curl -X POST http://localhost:8000/firewall -d '{"enabled": false}'
# 切换
curl -X POST http://localhost:8000/firewall
# 检查状态
curl http://localhost:8000/health | jq .firewall_enabled
```
### 配置文件配置(可选)
```
firewall:
enabled: false # default off
agent_config: "hb-firewall/agent.yaml" # HB security policy
model_path: null # optional Tier 2 model
```
### A/B 测试工作流
在关闭和开启防火墙的情况下运行相同的攻击会话,以衡量其有效性:
```
# 1. 在不开启 firewall 的情况下运行测试
airt-replay evidence/metabase.csv --session abc123 -o results/no-firewall.md
# 2. 启用 firewall
curl -X POST http://localhost:8000/firewall -d '{"enabled": true}'
# 3. 运行相同的测试
airt-replay evidence/metabase.csv --session abc123 -o results/with-firewall.md
# 4. 比较报告
```
需要 `pip install hb-firewall` —— 防火墙仅在首次启用时延迟加载。
## Token 刷新
两种独立的方法,按 `auth.token_refresh.order` 中配置的顺序尝试:
| Method | Config Key | Default | Use Case |
|---|---|---|---|
| `cli` | `auth.token_refresh.cli.command` | `gcloud auth print-access-token` | 本地开发、GCP、Azure、任何 CLI |
| `endpoint` | `auth.token_refresh.endpoint.url` | (无) | 通过 Cloudflare 隧道的远程令牌服务器 |
默认顺序为 `["cli"]`。要添加远程端点:
```
auth:
token_refresh:
order: ["cli", "endpoint"]
endpoint:
url: "https://token.example.com/token"
secret_env: TOKEN_SECRET
```
Token 刷新在聊天期间的 401/403 错误时自动触发,或通过 `POST /auth` 手动触发。
## 模拟服务器
模拟服务器使用与框架相同的映射器,因此它模拟目标的确切有线格式。任何对真实目标有效的工具对模拟器也同样有效。
```
# Echo 模式(快速,无 LLM)
python -m harness.mock --backend echo
# 本地 Ollama
python -m harness.mock --backend ollama --model llama3.2
# OpenAI
python -m harness.mock --backend openai --model gpt-4o-mini
# Anthropic
python -m harness.mock --backend anthropic
# Gemini
python -m harness.mock --backend gemini
# DeepSeek
python -m harness.mock --backend deepseek
```
API 密钥从环境变量中读取:`OPENAI_API_KEY`、`ANTHROPIC_API_KEY`、`GOOGLE_API_KEY` / `GEMINI_API_KEY`、`DEEPSEEK_API_KEY`。
## 聊天 GUI
一个基于 Gradio 的交互式聊天客户端,用于手动测试和探索。GUI 连接到框架,并自动从配置文件的 `display_name` 字段检测目标名称。
```
# 首先启动 harness
PROFILE=profiles/default/profile.yaml BACKEND=mock uvicorn harness.server:app --port 8000
# 启动 GUI(自动检测目标名称)
python -m harness.gui
# 自定义端口或公共链接
python -m harness.gui --port 7860 --share
```
在配置文件 YAML 中设置 `display_name` 以自定义 GUI 标题:
```
target: example
display_name: "My Target" # shown in GUI title and health endpoint
```
功能:
- 带有对话历史记录和会话管理的 **聊天面板**
- 显示完整目标响应的 **原始响应选项卡**(如果映射器将其保留在 `raw` 中,代理思维或护栏事件等特定于演练的字段会出现在此处)
- 用于验证/刷新身份验证的 **身份验证选项卡**
- 运行时在真实和模拟之间切换的 **后端切换**
- 显示累积 API 调用统计信息的 **情报选项卡**
- 显示框架配置的 **运行状况选项卡**
## 情报收集
通过框架的每个 API 调用都记录到 `/intel/responses.jsonl`:
```
{
"timestamp": "2026-04-07T14:30:00Z",
"session_id": "harness-abc123",
"backend": "real",
"target": "example",
"prompt": "What is an ISA?",
"answer": "An Individual Savings Account is...",
"raw": { "...": "full target response (engagement-specific fields live here)" },
"error": null
}
```
`raw` 字段保存目标返回的任何内容——包括任何自定义元数据、代理思维、护栏事件或其他特定于演练的数据。框架本身保持中立,不解析这些字段。
## 重放
针对正在运行的框架重放记录的会话,以进行回归测试。发送先前测试中的确切攻击者提示,并将新响应与原始响应进行比较。可以选择使用 LLM 评判器对每个轮次进行评分。
```
# 首先启动 harness(mock 或真实)
BACKEND=mock uvicorn harness.server:app --port 8000
```
### 两种源类型(自动检测)
| Source | Path | 工作原理 |
|---|---|---|
| **情报日志** | 目录或 `.jsonl` 文件 | 读取 `responses.jsonl`,按 session_id 分组,按时间戳排序 |
| **Metabase CSV** | `.csv` 文件 | 读取包含 `session_id`、`turn`、`request`/`prompt`、`answer`/`response` 列的 CSV |
情报日志是框架自动记录的内容(请参阅 [情报收集](#intel-collection))。Metabase CSV 是精选的子集,通常在演练期间生成,包含用于回归测试的选定会话。
### 列出会话
```
# 来自 intel 日志
airt-replay profiles/default/intel/ --list-sessions
# 来自 metabase CSV
airt-replay evidence/metabase.csv --list-sessions
```
### 重放会话
```
airt-replay evidence/metabase.csv --session abc123
```
支持部分会话 ID 匹配。重放使用新的会话 ID 将每个提示发送到框架 `/chat` 端点,并将新响应与原始响应进行比较。
### 评判评估
使用 LLM 评判器对每个重放的轮次进行通过/失败(PASS/FAIL)评分:
```
airt-replay evidence/metabase.csv --session abc123 \
--evaluate \
--judge-config replay/judge_config.yaml \
--judge-prompts replay/judge_prompts.yaml \
-o results/regression-report.md
```
评判配置和评判提示是特定于演练的文件——框架提供了多提供商框架。支持的评判提供商:
| Provider | Config key | Notes |
|---|---|---|
| AWS Bedrock | `bedrock` | 零数据保留;需要 `boto3` |
| Ollama (local) | `ollama` | 完全物理隔离;没有数据离开您的机器 |
| Google Gemini | `gemini` | 直接 API |
| Anthropic Claude | `claude` | 直接 API |
| OpenAI-compatible | (默认) | vLLM、RunPod、LiteLLM 或任何 chat/completions 端点 |
### Metabase 格式兼容性
重放适用于任何具有这四列的 CSV:
| Column | Required | 映射到 |
|---|---|---|
| `session_id` | 是 | 将轮次分组为会话 |
| `turn` | 是 | 在会话内对轮次进行排序 |
| `request` 或 `prompt` | 是 | 攻击者提示(逐字重放) |
| `answer` 或 `response` | 是 | 原始响应(用于比较) |
其他列(finding_id、scenario_id、护栏评分等)会被通用重放引擎忽略。特定于演练的包装器可以使用它们进行导航和报告。
### CLI 参考
| Flag | Purpose |
|---|---|
| `source` (positional) | 情报目录、`.jsonl` 或 `.csv` 的路径(默认:`.`) |
| `--list-sessions` | 列出中的所有会话 |
| `--session ID` | 重放会话(支持部分匹配) |
| `--harness-url URL` | 框架 URL(默认:`$HARNESS_URL` 或 `http://localhost:8000`) |
| `--delay SECONDS` | 轮次之间的延迟(默认:1) |
| `--evaluate` | 对重放的响应运行 LLM 评判器 |
| `--judge-config FILE` | 评判配置 YAML 的路径 |
| `--judge-prompts FILE` | 评判提示 YAML 的路径 |
| `--judge-criteria KEY` | 将单个条件键应用于所有轮次 |
| `-o FILE` | 将比较报告保存到文件 |
## 许可证
版权所有 (c) 2026 Deep Cyber Ltd。
根据 Apache License 2.0 版获得许可。有关详细信息,请参阅 [LICENSE](LICENSE)。
标签:AI红队, API网关, CISA项目, Garak, LLM评估, Mock模拟, Ollama, OpenAI兼容, Promptfoo, PyRIT, 中间件, 会话回放, 协议转换, 多智能体系统, 多语言支持, 大模型安全, 安全测试, 安全测试框架, 对话日志, 情报收集, 攻击性安全, 攻击模拟, 数据泄露, 时序数据库, 漏洞回归, 漏洞研究, 请求拦截, 逆向工具, 驱动签名利用