rajawajahat/opsrunbook-copilot
GitHub: rajawajahat/opsrunbook-copilot
一个运行在 AWS 上的智能事件响应流水线,自动采集故障证据、用 LLM 分析根因并执行 Jira 工单创建、通知推送和代码修复 PR 等响应动作。
Stars: 0 | Forks: 0
# OpsRunbook Copilot
[](https://python.org)
[](https://github.com/langchain-ai/langgraph)
[](https://aws.amazon.com)
[](https://terraform.io)
[](LICENSE)
**一个开源的智能事件响应管道,可监控您的 AWS 服务,使用 LLM 分析错误,并自动执行以下操作:**
- 创建包含结构化发现的 **Jira 工单**
- 发送 **Teams / Slack 通知**
- 提交包含建议代码修复的 **GitHub Pull Request** —
然后根据审查者的反馈自主进行迭代
所有操作均在您自己的 AWS 账户中运行。除 LLM API 调用(Groq 或 Google Gemini — 可灵活替换)外,没有任何数据会离开您的基础设施。
## 工作原理
```
Alert / manual trigger
│
▼
┌─────────────────────┐
│ FastAPI (local │ POST /v1/incidents
│ or Lambda+APIGW) │
└──────────┬──────────┘
│ starts
▼
┌─────────────────────────────────────────────────────┐
│ Step Functions Orchestrator │
│ ┌──────────────┐ ┌───────────┐ ┌───────────────┐ │
│ │ collector_ │ │collector_ │ │ collector_ │ │
│ │ logs │ │ metrics │ │ stepfn │ │
│ └──────────────┘ └───────────┘ └───────────────┘ │
│ └──────────┬──────────┘ │
│ ▼ │
│ snapshot_persist Lambda │
└─────────────────────────┬───────────────────────────┘
│ EventBridge
▼
┌───────────────────────┐
│ Analyzer Lambda │ LLM → IncidentPacket
│ (Groq / Gemini) │ findings, hypotheses,
└───────────┬───────────┘ suspected_owners
│ EventBridge
▼
┌───────────────────────┐
│ Actions Runner Lambda│ → Jira ticket
│ │ → Teams notification
└───────────┬───────────┘ → GitHub PR (simple)
│ EventBridge
▼
┌───────────────────────┐
│ Coding Agent Lambda │ LangGraph ReAct agent
│ (LangGraph + Groq) │ → GitHub PR (code fix)
└───────────────────────┘
GitHub PR review comment → pr_review_cycle → LLM fix → commit
```
## 前置条件
| 需求 | 说明 |
|---|---|
| AWS 账户 | 具有下列权限的 IAM 用户/角色 |
| Terraform ≥ 1.5 | [安装](https://developer.hashicorp.com/terraform/install) |
| Python 3.11+ | 用于在本地运行 API 和测试 |
| Groq API 密钥 **或** Google Gemini API 密钥 | 免费套餐即可。或使用 `llm_provider = "stub"`,通过确定性启发式算法在无 LLM 的情况下运行 |
| Jira Cloud 账户 | 用于创建工单(可选 — 可通过 `ACTIONS_DRY_RUN=true` 禁用) |
| GitHub App 或 PAT | 用于开启修复 PR(可选) |
| Teams 入站 Webhook | 用于发送通知(可选) |
## 快速入门(5 步)
### 1. 克隆并配置 Python 环境
```
git clone https://github.com/rajawajahat/opsrunbook-copilot.git
cd opsrunbook-copilot
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e "packages/contracts"
pip install -r services/api/src/../../../requirements.txt 2>/dev/null || true
pip install fastapi uvicorn boto3 pydantic python-dotenv
```
### 2. 配置 Terraform
```
cd infra/terraform/envs/dev
# 复制示例并填入您的值
cp terraform.tfvars.example terraform.tfvars
# 编辑 terraform.tfvars — 设置 aws_profile、github_owner 等
```
### 3. 部署 AWS 基础设施
```
# 从 infra/terraform/envs/dev/
terraform init
terraform plan # review what will be created
terraform apply
```
这将创建:S3 存储桶、DynamoDB 表、Lambda 函数、Step Functions 状态机、EventBridge 总线、IAM 角色以及 SSM 参数容器。
### 4. 在 SSM 中设置密钥值
Terraform 创建了带有占位符值的 SSM 参数**容器**。
您必须手动设置真实值(切勿通过 Terraform 设置):
```
# LLM API key(选择一个)
aws ssm put-parameter --name /opsrunbook/dev/groq/api_key \
--value "YOUR_GROQ_KEY" --type SecureString --overwrite
# 或用于 Gemini
aws ssm put-parameter --name /opsrunbook/dev/google/api_key \
--value "YOUR_GOOGLE_KEY" --type SecureString --overwrite
# GitHub PAT(需要 repo + pull_requests 权限)
aws ssm put-parameter --name /opsrunbook/dev/github/token \
--value "ghp_yourtoken" --type SecureString --overwrite
# Jira 凭据
aws ssm put-parameter --name /opsrunbook/dev/jira/base_url \
--value "https://your-org.atlassian.net" --type String --overwrite
aws ssm put-parameter --name /opsrunbook/dev/jira/email \
--value "your@email.com" --type String --overwrite
aws ssm put-parameter --name /opsrunbook/dev/jira/api_token \
--value "YOUR_JIRA_TOKEN" --type SecureString --overwrite
aws ssm put-parameter --name /opsrunbook/dev/jira/project_key \
--value "OPS" --type String --overwrite
# Teams webhook(可选)
aws ssm put-parameter --name /opsrunbook/dev/teams/webhook_url \
--value "https://your-org.webhook.office.com/..." --type SecureString --overwrite
# GitHub webhook secret(用于 PR 审查周期)
aws ssm put-parameter --name /opsrunbook/dev/github/webhook_secret \
--value "$(openssl rand -hex 32)" --type SecureString --overwrite
```
### 5. 配置并启动 API
```
cd services/api
# 复制 .env.example 并填入来自 terraform output 的值
cp .env.example .env
# 获取 Terraform 输出
cd ../../infra/terraform/envs/dev
terraform output
# 将这些填入 services/api/.env:
# EVIDENCE_BUCKET、INCIDENTS_TABLE、SNAPSHOTS_TABLE、PACKETS_TABLE
# STATE_MACHINE_ARN、EVENT_BUS_NAME
# 生成 API key 并添加到 .env
python -c "import secrets; print(secrets.token_urlsafe(32))"
# 添加:API_KEY=<生成的值>
# 启动 API
cd ../../services/api
aws-vault exec -- bash -c \
'PYTHONPATH=src:../../packages/contracts/src \
PLAN_GENERATOR_PATH=$(pwd)/../../infra/terraform/modules/actions_runner/src \
../../.venv/bin/uvicorn src.app:app --port 8100 --log-level info'
```
### 运行冒烟测试
```
cd /path/to/opsrunbook-copilot
export GITHUB_OWNER=your-github-org
API_URL=http://127.0.0.1:8100 bash scripts/smoke_it5.sh
```
## 所需的 AWS IAM 权限
Terraform 和运行中的 Lambda 所使用的 IAM 主体(用户或角色)需要以下权限。请为 Terraform 部署和 Lambda 执行使用独立的角色(最小权限原则)。
### Terraform 部署角色
```
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["s3:*"], "Resource": "arn:aws:s3:::opsrunbook-copilot-*" },
{ "Effect": "Allow", "Action": ["dynamodb:*"], "Resource": "arn:aws:dynamodb:*:*:table/opsrunbook-copilot-*" },
{ "Effect": "Allow", "Action": ["lambda:*"], "Resource": "arn:aws:lambda:*:*:function:opsrunbook-copilot-*" },
{ "Effect": "Allow", "Action": ["states:*"], "Resource": "arn:aws:states:*:*:stateMachine:opsrunbook-copilot-*" },
{ "Effect": "Allow", "Action": ["events:*"], "Resource": "*" },
{ "Effect": "Allow", "Action": ["iam:*"], "Resource": "arn:aws:iam::*:role/opsrunbook-copilot-*" },
{ "Effect": "Allow", "Action": ["ssm:PutParameter","ssm:GetParameter","ssm:DeleteParameter","ssm:DescribeParameters"], "Resource": "arn:aws:ssm:*:*:parameter/opsrunbook/*" },
{ "Effect": "Allow", "Action": ["logs:*"], "Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/opsrunbook-copilot-*" }
]
}
```
### Lambda 执行角色(由 Terraform 自动创建)
每个 Lambda 仅被授予其所需的权限:
| Lambda | 主要权限 |
|---|---|
| `collector_logs` | `logs:StartQuery`, `logs:GetQueryResults`, `s3:PutObject`, `events:PutEvents` |
| `collector_metrics` | `cloudwatch:GetMetricData`, `s3:PutObject`, `events:PutEvents` |
| `collector_stepfn` | `states:DescribeExecution`, `states:ListExecutions`, `s3:PutObject`, `events:PutEvents` |
| `snapshot_persist` | `s3:GetObject`, `s3:PutObject`, `dynamodb:PutItem`, `events:PutEvents` |
| `analyzer` | `s3:GetObject`, `s3:PutObject`, `dynamodb:PutItem`, `events:PutEvents`, `ssm:GetParameter` |
| `actions_runner` | `s3:GetObject`, `dynamodb:PutItem`, `dynamodb:Query`, `events:PutEvents`, `ssm:GetParameter` |
| `coding_agent` | `s3:GetObject`, `dynamodb:PutItem`, `events:PutEvents`, `ssm:GetParameter` |
| `pr_review_cycle` | `s3:GetObject`, `s3:PutObject`, `dynamodb:PutItem`, `ssm:GetParameter` |
## 配置参考
### `services/api/.env`
| 变量 | 必填 | 描述 |
|---|---|---|
| `API_KEY` | 是 | 用于 `X-API-Key` 请求头认证的随机密钥。生成方式:`python -c "import secrets; print(secrets.token_urlsafe(32))"` |
| `AWS_REGION` | 是 | AWS 区域(例如 `us-east-1`) |
| `EVIDENCE_BUCKET` | 是 | S3 存储桶名称(来自 `terraform output evidence_bucket`) |
| `INCIDENTS_TABLE` | 是 | DynamoDB 表(来自 `terraform output incidents_table`) |
| `SNAPSHOTS_TABLE` | 是 | DynamoDB 表(来自 `terraform output snapshots_table`) |
| `PACKETS_TABLE` | 是 | DynamoDB 表(来自 `terraform output packets_table`) |
| `STATE_MACHINE_ARN` | 是 | Step Functions ARN(来自 `terraform output state_machine_arn`) |
| `EVENT_BUS_NAME` | 是 | EventBridge 总线名称(来自 `terraform output event_bus_name`) |
| `GITHUB_WEBHOOK_SECRET` | 用于 PR 审查 | 必须与 SSM `/opsrunbook/dev/github/webhook_secret` 中的值相匹配 |
| `GITHUB_APP_SLUG` | 用于 PR 审查 | 您的 GitHub App slug(例如 `opsrunbook-copilot-bot`) |
| `PR_REVIEW_STATE_MACHINE_ARN` | 用于 PR 审查 | 来自 `terraform output pr_review_state_machine_arn` |
| `PLAN_GENERATOR_PATH` | 本地开发 | 用于 replay 端点的 `infra/terraform/modules/actions_runner/src` 路径 |
| `MAX_ROWS_PER_QUERY` | 否 | CloudWatch Insights 行预算(默认:`100`) |
| `MAX_BYTES_TOTAL` | 否 | 证据字节预算(默认:`200000`) |
| `MAX_TIME_WINDOW_MINUTES` | 否 | 最大分析时间窗口(默认:`15`) |
### SSM 参数(手动设置 — 切勿通过 Terraform 设置)
| SSM 路径 | 类型 | 描述 |
|---|---|---|
| `/opsrunbook/dev/groq/api_key` | SecureString | Groq API 密钥 |
| `/opsrunbook/dev/google/api_key` | SecureString | Google Gemini API 密钥 |
| `/opsrunbook/dev/github/token` | SecureString | GitHub PAT(需要 `repo` + `pull_requests` 权限范围) |
| `/opsrunbook/dev/github/webhook_secret` | SecureString | 在您的 GitHub App 中注册的 HMAC 密钥 |
| `/opsrunbook/dev/jira/base_url` | String | `https://your-org.atlassian.net` |
| `/opsrunbook/dev/jira/email` | String | Jira 用户邮箱 |
| `/opsrunbook/dev/jira/api_token` | SecureString | Jira API token |
| `/opsrunbook/dev/jira/project_key` | String | Jira 项目键(例如 `OPS`) |
| `/opsrunbook/dev/jira/issue_type` | String | 问题类型(默认:`Bug`) |
| `/opsrunbook/dev/teams/webhook_url` | SecureString | Teams 入站 Webhook URL |
### `infra/terraform/envs/dev/terraform.tfvars`
| 变量 | 描述 |
|---|---|
| `aws_region` | AWS 区域 |
| `aws_profile` | AWS CLI 配置文件名称 |
| `github_owner` | 拥有目标仓库的 GitHub 组织或用户名 |
| `github_default_branch` | 用于修复 PR 的默认分支(默认:`main`) |
| `github_app_slug` | 用于自身事件过滤的 GitHub App slug |
| `llm_provider` | `groq` \| `gemini` \| `stub` |
| `evidence_retention_days` | S3 对象保留期(默认:`7`) |
## 调用 API
所有端点(`GET /health` 除外)均需要 `X-API-Key` 请求头。
```
export API=http://127.0.0.1:8100
export API_KEY=your-api-key-here
# 触发 incident 分析
curl -X POST "$API/v1/incidents" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": "incident_event.v1",
"event_id": "evt-unique-id-001",
"service": "payment-service",
"environment": "prod",
"severity": "critical",
"time_window": {
"start": "2026-04-06T20:00:00Z",
"end": "2026-04-06T20:15:00Z"
},
"hints": {
"log_groups": ["/aws/lambda/payment-service"]
}
}'
# 轮询 orchestrator 状态
curl -H "X-API-Key: $API_KEY" \
"$API/v1/incidents/{incident_id}/runs/{collector_run_id}"
# 获取 LLM 分析
curl -H "X-API-Key: $API_KEY" \
"$API/v1/incidents/{incident_id}/packet/latest"
# 获取 Jira/Teams/PR 操作结果
curl -H "X-API-Key: $API_KEY" \
"$API/v1/incidents/{incident_id}/actions/latest"
```
## 适配您的服务
### 将其指向您自己的 CloudWatch 日志组
在 `POST /v1/incidents` 请求体中,将 `hints.log_groups` 设置为您应用程序的日志组:
```
"hints": {
"log_groups": [
"/aws/lambda/my-payment-service",
"/aws/ecs/my-payment-processor",
"/aws/rds/my-db-errors"
]
}
```
### 添加 CloudWatch 指标查询
```
"hints": {
"log_groups": ["/aws/lambda/my-service"],
"metric_queries": [
{
"namespace": "AWS/Lambda",
"metric_name": "Errors",
"dimensions": {"FunctionName": "my-service"},
"period": 300,
"stat": "Sum"
}
]
}
```
### 将服务映射到 GitHub 仓库
创建 `infra/terraform/modules/analyzer/src/resource_repo_map.json`:
```
{
"payment-service": "your-org/payment-service",
"auth-service": "your-org/auth-service",
"order-processor": "your-org/order-processor"
}
```
这会告知 analyzer 哪个仓库拥有哪个服务,以便 coding agent 能够向正确的仓库提交修复 PR。
### 禁用您不需要的自动化操作
```
# Dry-run 模式:分析并创建 Jira,但不打开 GitHub PR
ACTIONS_DRY_RUN=true
# Kill switch:仅分析,完全不进行外部操作
AUTOMATION_ENABLED=false
# 使用 stub LLM(无需 API key,确定性启发式)
# 在 terraform.tfvars 中设置:
llm_provider = "stub"
```
## 本地开发
```
# 运行所有测试
bash scripts/test.sh
# Lint
bash scripts/lint.sh
# Smoke test:完整流水线(需要 AWS + API 运行中)
export GITHUB_OWNER=your-github-org
API_URL=http://127.0.0.1:8100 bash scripts/smoke_it5.sh
# Smoke test:webhook → PR 审查周期
GITHUB_WEBHOOK_SECRET= GITHUB_REPO=owner/repo PR_NUMBER=17 \
API_URL=http://127.0.0.1:8100 bash scripts/smoke_it6.sh
```
### 在本地运行 coding agent(不使用 Lambda)
```
cd /path/to/opsrunbook-copilot
export GROQ_API_KEY=your-key
export GITHUB_TOKEN=ghp_yourtoken
python -m packages.agent.runner \
--packet-file tests/fixtures/sample_packet.json \
--repo your-org/your-repo \
--dry-run # omit --dry-run to actually open a PR
```
## 安全说明
- **密钥**:所有 API 密钥和令牌均存储在 AWS SSM Parameter Store(SecureString)中。它们绝不会出现在 Terraform 状态、环境文件或源代码中。
- **API 认证**:FastAPI 层要求在所有路由(`GET /health` 除外)上提供 `X-API-Key` 请求头。在生产环境中,请将其部署在 VPC 或带有额外网络控制措施的 API Gateway 之后。
- **GitHub webhooks**:使用 `hmac.compare_digest`(时间安全)通过 HMAC-SHA256 进行验证。
- **证据脱敏**:日志在持久化之前,会扫描其中是否包含令牌、API 密钥、密码、AWS 凭证和连接字符串。
- **LLM 数据**:仅将经过脱敏处理的证据文本发送给 LLM 提供商。绝不应转发包含机密的原始日志行。
- **IAM**:Lambda 执行角色遵循最小权限原则(参见上方权限表)。绝不授予宽泛的 `*` 操作权限。
## 项目结构
```
opsrunbook-copilot/
├── packages/
│ ├── agent/ # LangGraph ReAct coding agent
│ ├── contracts/ # Pydantic v2 shared schemas (installable package)
│ └── llm/ # Shared LLM client (Groq / Gemini / stub)
├── services/
│ ├── api/ # FastAPI entry point + routers + stores
│ └── collectors/ # CloudWatch / Step Functions collector library
├── infra/terraform/
│ ├── envs/dev/ # Dev environment wiring (main.tf, variables.tf)
│ └── modules/ # One module per Lambda function
│ ├── actions_runner/
│ ├── analyzer/
│ ├── coding_agent/
│ ├── collector_logs/
│ ├── collector_metrics/
│ ├── collector_stepfn/
│ ├── orchestrator/
│ ├── pr_review_cycle/
│ ├── snapshot_persist/
│ └── storage/
├── tests/ # Integration tests + fixtures
└── scripts/ # smoke_it*.sh, lint.sh, test.sh
```
## 许可证
MIT
标签:AIOps, AV绕过, AWS, ChatOps, DevSecOps, DPI, ECS, FastAPI, GitHub自动修复, Jira集成, LangGraph, PB级数据处理, Python, Serverless, Slack通知, SRE, Step Functions, Terraform, 上游代理, 代码审查自动化, 偏差过滤, 基于证据的响应, 多云管理, 安全运维, 报警聚合, 无后门, 模块化设计, 自动化修复, 自动化运维, 逆向工具