Files
agent_management/.omc/plans/code_ai_agent_cicd.md
T

20 KiB
Raw Blame History

code_ai_agent CI/CD 工作流方案设计

计划文件: .omc/plans/code_ai_agent_cicd.md 创建日期: 2026-03-27 状态: 待用户确认


1. 方案概述

将 code_ai_agent 从单纯的代码生成服务升级为具备完整 DevOps 工作流能力的「代码员工 Agent」。新增 Git 操作、SSH 远程执行、K8s 部署触发能力,全部通过 HTTP API 暴露。

完整工作流

外部调用方 (agent-manager / 人工)
          │
          ▼
   code_ai_agent Pod
   ┌──────────────────────────────────────────┐
   │  api_server.py  (HTTP 路由层)            │
   │  ┌──────────┬──────────┬──────────────┐  │
   │  │ /git/*   │ /ssh/*   │ /deploy/k8s  │  │
   │  └────┬─────┴────┬─────┴──────┬───────┘  │
   │       │          │            │           │
   │  src/server/tools/ (工具实现层)            │
   │  ┌────▼─────┐ ┌──▼──────┐ ┌──▼────────┐  │
   │  │git_tools │ │ssh_tools│ │deploy_tools│ │
   │  └────┬─────┘ └──┬──────┘ └──┬────────┘  │
   │       │          │            │           │
   │  /workspace/{task_id}/  (隔离工作空间)     │
   └───┬───┴──────────┴────────────┴───────────┘
       │
       ├─► Gitee (http://gitee.ath.cx:3000)
       ├─► Azure VM (SSH 22)
       └─► K8s API Server

典型工作流序列

1. POST /api/v1/git/clone        → 克隆仓库到 /workspace/{task_id}
2. POST /api/v1/git/branch       → 创建 feature/xxx 分支
3. POST /api/v1/code/generate    → 使用现有能力生成/修改代码
4. POST /api/v1/git/status       → 确认变更
5. POST /api/v1/git/commit-push  → 提交并推送
6. POST /api/v1/ssh/exec         → SSH 到 Azure VM 执行测试
7. POST /api/v1/deploy/k8s       → 测试通过后触发 K8s 部署

2. 新增 API 端点设计(api_server.py)

2.1 Git 操作端点

POST /api/v1/git/clone

// 请求
{
  "repo_url": "http://gitee.ath.cx:3000/zhanggangyong/agent_management.git",
  "task_id": "task-20260327-001",
  "branch": "main",
  "depth": 1
}
// 响应
{
  "success": true,
  "task_id": "task-20260327-001",
  "workspace": "/workspace/task-20260327-001",
  "branch": "main",
  "commit": "abc1234"
}

POST /api/v1/git/branch

// 请求
{
  "task_id": "task-20260327-001",
  "branch_name": "feature/auto-fix-bug-123",
  "from_branch": "main"
}
// 响应
{ "success": true, "branch": "feature/auto-fix-bug-123", "base_commit": "abc1234" }

POST /api/v1/git/status

// 请求
{ "task_id": "task-20260327-001" }
// 响应
{
  "success": true,
  "branch": "feature/auto-fix-bug-123",
  "staged": ["src/main.py"],
  "unstaged": ["README.md"],
  "untracked": ["new_file.py"],
  "raw_output": "M  src/main.py\n?? new_file.py"
}

POST /api/v1/git/commit-push

// 请求
{
  "task_id": "task-20260327-001",
  "message": "fix: resolve null pointer in agent executor",
  "files": ["src/agent.py"],
  "push": true
}
// 响应
{ "success": true, "commit": "def5678", "pushed": true, "branch": "feature/auto-fix-bug-123" }

POST /api/v1/git/diff

// 请求
{ "task_id": "task-20260327-001", "staged": false }
// 响应
{ "success": true, "diff": "--- a/src/main.py\n+++ b/src/main.py\n..." }

2.2 SSH 操作端点

POST /api/v1/ssh/exec

// 请求
{
  "host": "<azure-vm-ip>",
  "user": "azureuser",
  "command": "cd /app && pytest tests/ -v --tb=short",
  "timeout": 300,
  "task_id": "task-20260327-001"
}
// 响应
{
  "success": true,
  "exit_code": 0,
  "stdout": "collected 42 items ... 42 passed",
  "stderr": "",
  "duration_seconds": 45.2
}

说明: host 若不传,从环境变量 SSH_TEST_HOST 读取;user 从 SSH_USER 读取,默认 azureuser。

2.3 部署端点

POST /api/v1/deploy/k8s

// 请求
{
  "namespace": "agent-manager",
  "deployment": "agent-manager",
  "image": "agnettaiji.azurecr.io/ai-agents/agent-manager:v1.2.3",
  "strategy": "set-image",
  "wait": true,
  "timeout": 300
}
// strategy: "rollout-restart" | "set-image"
// 响应
{ "success": true, "deployment": "agent-manager", "status": "rolled out", "duration_seconds": 62 }

3. 新增工具函数设计(mcp_server.py + tools/ 模块)

3.1 文件结构变化

agent_templates/agents/code_ai_agent/
├── Dockerfile                    # 修改:增加 git/ssh/kubectl
├── requirements.txt              # 修改:增加 paramiko, gitpython
├── src/server/
│   ├── api_server.py             # 修改:新增 /git /ssh /deploy 路由
│   ├── mcp_server.py             # 修改:新增工具注册
│   ├── mcp_http_server.py        # 不变
│   └── tools/                   # 新增目录
│       ├── __init__.py
│       ├── git_tools.py          # Git 操作实现
│       ├── ssh_tools.py          # SSH 操作实现
│       ├── deploy_tools.py       # K8s 部署实现
│       └── workspace.py          # 工作空间管理
└── k8s/                          # 新增:agent 专属 K8s 配置
    ├── code-ai-agent-deployment.yaml
    └── code-ai-agent-secret.yaml

3.2 git_tools.py 核心接口

class GitTools:
    def __init__(self):
        self.workspace_root = "/workspace"
        self._gitee_user = os.getenv("GITEE_USERNAME")
        self._gitee_token = os.getenv("GITEE_TOKEN")

    def clone(self, repo_url, task_id, branch="main", depth=1) -> dict
    def create_branch(self, task_id, branch_name, from_branch=None) -> dict
    def get_status(self, task_id) -> dict
    def stage_files(self, task_id, files=None) -> dict   # None = git add -A
    def commit(self, task_id, message) -> dict
    def push(self, task_id, branch=None) -> dict
    def get_diff(self, task_id, staged=False) -> dict
    def cleanup(self, task_id) -> dict                   # 删除工作空间

    def _inject_credentials(self, repo_url) -> str:
        # http://user:token@gitee.ath.cx:3000/...
        parsed = urlparse(repo_url)
        return parsed._replace(
            netloc=f"{self._gitee_user}:{self._gitee_token}@{parsed.hostname}:{parsed.port}"
        ).geturl()

    def _run(self, cmd, cwd) -> tuple[int, str, str]
        # subprocess.run,捕获 stdout/stderr,设置超时

3.3 ssh_tools.py 核心接口

class SSHTools:
    def __init__(self):
        self._key_path = "/root/.ssh/id_rsa"      # 从 Secret 挂载
        self._default_host = os.getenv("SSH_TEST_HOST")
        self._default_user = os.getenv("SSH_USER", "azureuser")

    def exec(self, command, host=None, user=None, timeout=120, task_id=None) -> dict:
        # 使用 paramiko 连接,执行命令,返回 stdout/stderr/exit_code
        # 每次调用建立新连接,操作完毕后关闭

    def _get_client(self, host, user) -> paramiko.SSHClient

3.4 deploy_tools.py 核心接口

class DeployTools:
    def __init__(self):
        # 优先使用挂载的 kubeconfig,其次 in-cluster config
        self._kubeconfig = "/root/.kube/config"

    def rollout_restart(self, namespace, deployment, wait=True, timeout=300) -> dict
    def set_image(self, namespace, deployment, image, wait=True, timeout=300) -> dict
    def get_status(self, namespace, deployment) -> dict
    def _run_kubectl(self, args) -> tuple[int, str, str]

3.5 workspace.py — 工作空间管理

class WorkspaceManager:
    ROOT = "/workspace"

    @staticmethod
    def get_path(task_id: str) -> str:
        # 返回 /workspace/{task_id}
        # task_id 只允许 [a-zA-Z0-9_-],防止路径注入

    @staticmethod
    def create(task_id: str) -> str

    @staticmethod
    def cleanup(task_id: str) -> None

    @staticmethod
    def list_tasks() -> list[str]

    @staticmethod
    def disk_usage() -> dict   # 返回各 task_id 占用磁盘大小

4. 安全设计

4.1 SSH 私钥注入

方案:K8s Secret → Volume Mount(只读)

# 新建 Secret(在 code-ai-agent 命名空间下)
apiVersion: v1
kind: Secret
metadata:
  name: code-ai-agent-ssh-secret
  namespace: agent-manager
type: Opaque
data:
  id_rsa: <base64-encoded-private-key>
  id_rsa.pub: <base64-encoded-public-key>
  known_hosts: <base64-encoded-known_hosts>   # 预置 Azure VM


# Deployment volumeMounts
volumeMounts:
- name: ssh-secret
  mountPath: /root/.ssh
  readOnly: true
volumes:
- name: ssh-secret
  secret:
    secretName: code-ai-agent-ssh-secret
    defaultMode: 0400   # 私钥必须 0400,否则 SSH 拒绝

初始化:容器 entrypoint 或 initContainer 执行 chmod 700 /root/.ssh && chmod 600 /root/.ssh/id_rsa。

4.2 Git 凭证安全传递

方案 说明 推荐度
Token 嵌入 URL http://user:token@host/repo 内存拼接,不落盘 P0 首选
git credential store 写入 ~/.git-credentials 文件权限 600 备选
SSH key for git gitee 配置 deploy key,统一 SSH P2 升级

实现要点:_inject_credentials() 在内存拼接带 token 的 URL;clone 完成后用 git remote set-url origin <无密码URL> 替换;日志中对 URL 做 token 脱敏。

4.3 权限隔离

  • code_ai_agent 使用独立 ServiceAccount code-ai-agent
  • RBAC 只授予 agent-manager 命名空间下 Deployment 的 get/patch/update
  • SSH 连接只允许白名单 host(SSH_ALLOWED_HOSTS 环境变量,ssh_tools.py 校验)
  • /workspace 挂载独立 emptyDir,不与其他 agent 共享
  • API 通过现有 X-API-Key header 鉴权

5. 工作空间设计

5.1 目录结构

/workspace/
├── task-20260327-001/
│   ├── agent_management/       # 克隆的仓库
│   └── .meta.json              # 任务元数据(时间、branch、状态)
├── task-20260327-002/
│   └── agent_management/
└── .workspace_index.json

5.2 并发隔离策略

  • task_id 由调用方传入或服务端 uuid4() 自动生成
  • 每个 task_id 对应独立目录,无共享文件
  • 任务完成后调用清理接口或设置 TTL 自动清理
  • 磁盘告警:workspace 总占用超过 10GB 返回 503
  • task_id 只允许 [a-zA-Z0-9_-],防止路径穿越注入

5.3 新增管理端点

GET    /api/v1/workspace/list          → 列出所有 task_id 和磁盘占用
DELETE /api/v1/workspace/{task_id}     → 清理指定工作空间

6. Dockerfile 修改

当前状态: 只安装 gcc,无 git/ssh/kubectl。

修改后关键变更:

FROM python:3.12-slim

WORKDIR /app
ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1

# 新增:git + openssh-client + curl(kubectl 安装需要)
RUN apt-get update && apt-get install -y \
    gcc git openssh-client curl ca-certificates gnupg \
    && rm -rf /var/lib/apt/lists/*

# 新增:安装 kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
    && chmod +x kubectl && mv kubectl /usr/local/bin/

# 新增:paramiko(SSH)、gitpython(可选,subprocess git 为主)
RUN pip install --no-cache-dir -r requirements.txt requests paramiko gitpython

# 新增:工作空间目录(PVC 挂载时会覆盖)
RUN mkdir -p /workspace /tmp/projects

EXPOSE 8000 8001
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1
CMD ["python", "run_api_server.py"]

镜像大小预估影响: git + openssh ≈ +30MB,kubectl ≈ +50MB,paramiko ≈ +5MB。总增量约 85MB,可接受。


7. K8s 部署配置修改

7.1 新增文件:code-ai-agent-deployment.yaml

code_ai_agent 需要独立 Deployment(与 agent-manager 主服务分离),关键新增配置段:

spec:
  template:
    spec:
      serviceAccountName: code-ai-agent
      containers:
      - name: code-ai-agent
        env:
        - name: GITEE_USERNAME
          valueFrom:
            secretKeyRef:
              name: agent-manager-secret
              key: GITEE_USERNAME
        - name: GITEE_TOKEN
          valueFrom:
            secretKeyRef:
              name: agent-manager-secret
              key: GITEE_TOKEN
        - name: SSH_TEST_HOST
          valueFrom:
            secretKeyRef:
              name: code-ai-agent-ssh-secret
              key: SSH_TEST_HOST
        - name: SSH_USER
          value: "azureuser"
        volumeMounts:
        - name: ssh-secret
          mountPath: /root/.ssh
          readOnly: true
        - name: kubeconfig
          mountPath: /root/.kube
          readOnly: true
        - name: workspace
          mountPath: /workspace
        resources:
          requests:
            memory: "512Mi"
            cpu: "300m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
      volumes:
      - name: ssh-secret
        secret:
          secretName: code-ai-agent-ssh-secret
          defaultMode: 0400
      - name: kubeconfig
        secret:
          secretName: kubeconfig-secret
          optional: true
      - name: workspace
        emptyDir:
          sizeLimit: 20Gi

7.2 agent-manager-secret 新增 key

在现有 k8s/agent-manager-secret.yaml 补充:

  GITEE_USERNAME: "zhanggangyong"

7.3 新建 code-ai-agent-ssh-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: code-ai-agent-ssh-secret
  namespace: agent-manager
type: Opaque
data:
  id_rsa: <base64-encoded-private-key>
  known_hosts: <base64-encoded-known_hosts>
  SSH_TEST_HOST: <base64-encoded-azure-vm-ip>

7.4 RBAC 新增 Role + RoleBinding

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: code-ai-agent-role
  namespace: agent-manager
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "patch", "update"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]

8. 实现优先级

P0 — 核心能力(第一阶段,必须先完成)

编号 内容 验收标准
P0-1 Dockerfile 安装 git + openssh-client + kubectl docker run ... git --version 输出正常
P0-2 workspace.py 工作空间管理 单元测试覆盖路径注入防护(task_id 含 ../ 时拒绝)
P0-3 git_tools.py:clone + branch + status + commit + push 成功 clone gitee 仓库,创建分支并推送
P0-4 ssh_tools.py:exec SSH 到 Azure VM 执行 echo ok,返回 exit_code=0
P0-5 api_server.py 新增 /git/* 和 /ssh/exec 路由 HTTP 调用返回正确 JSON,异常时返回 4xx/5xx
P0-6 SSH Secret + Volume Mount K8s 配置 Pod 启动后 /root/.ssh/id_rsa 权限为 0400

P1 — 完整工作流(第二阶段)

编号 内容 验收标准
P1-1 deploy_tools.py:rollout-restart + set-image 成功触发 K8s 滚动更新,等待就绪返回
P1-2 api_server.py 新增 /deploy/k8s 路由 调用后 deployment 完成更新,status 字段正确
P1-3 RBAC:code-ai-agent ServiceAccount + Role kubectl auth can-i patch deployment 返回 yes
P1-4 git diff 接口 返回正确 unified diff 格式
P1-5 workspace list/cleanup 管理端点 GET /workspace/list 返回含磁盘占用的列表
P1-6 mcp_server.py 注册新工具 MCP 工具列表中出现 git_clone、ssh_exec、k8s_deploy

P2 — 增强与优化(第三阶段)

编号 内容 说明
P2-1 替换 HTTP token 为 SSH key 方式访问 git 更安全,需 gitee 配置 deploy key
P2-2 workspace 磁盘告警 + TTL 自动清理 防止 emptyDir 耗尽,定时任务每小时扫描
P2-3 SSH 连接池(paramiko Transport 复用) 减少高频调用连接建立开销
P2-4 /api/v1/pipeline/run 编排端点 单次调用完成 clone→修改→测试→部署全流程
P2-5 操作审计日志(structured log) 所有 git/ssh/deploy 操作可追溯,含 task_id

9. 潜在风险与注意事项

风险 1:Git Token 泄露

  • 场景: token 嵌入 URL 后被 git remote -v、进程环境变量或日志打印
  • 缓解: clone 后立即 git remote set-url origin <无密码URL>;日志中 URL 做正则脱敏;不将 token 写入任何文件

风险 2:workspace 磁盘耗尽

  • 场景: 大量任务未清理,emptyDir 超限导致 Pod 被驱逐
  • 缓解: emptyDir 设 sizeLimit: 20Gi;API 层磁盘检查(超 10GB 返回 503);P2 阶段加 TTL 自动清理

风险 3:SSH 私钥被容器内进程读取

  • 场景: 容器内其他进程或代码执行漏洞读取 /root/.ssh/id_rsa
  • 缓解: Volume defaultMode: 0400;容器以非 root 用户运行(P2 阶段);考虑使用 Vault Agent Injector 替代 Secret Volume

风险 4:K8s 部署权限过宽

  • 场景: code_ai_agent 被攻击后可滥用 kubectl 权限影响其他服务
  • 缓解: RBAC 严格限制到 agent-manager 命名空间,只允许 get/patch/update Deployment;禁止 delete、exec、secret 等危险操作

风险 5:并发 git 操作冲突

  • 场景: 两个任务使用相同 task_id 或同一仓库并发操作
  • 缓解: task_id 全局唯一(UUID);每个 task_id 独立目录;api_server.py 对同一 task_id 的写操作加文件锁

风险 6:Azure VM SSH 连接超时或不可达

  • 场景: 网络抖动或 VM 重启导致 SSH 命令挂起
  • 缓解: paramiko 设置 banner_timeout、auth_timeout、timeout;所有 ssh.exec 调用强制设置 timeout 参数(默认 120s);超时后返回明确错误而非挂起

风险 7:CI/CD 循环触发

  • 场景: code_ai_agent 推送代码触发 CI,CI 再触发 code_ai_agent,形成死循环
  • 缓解: commit message 加 [skip-ci] 标记;部署端点需要明确的 image tag 参数,不自动推断

10. 工作计划(Task Flow)

Step 1:基础设施准备(P0-1, P0-6)

  • 修改 Dockerfile,安装 git/openssh/kubectl
  • 创建 code-ai-agent-ssh-secret.yaml
  • 更新 agent-manager-secret.yaml 补充 GITEE_USERNAME
  • 验收: Pod 启动正常,/root/.ssh/id_rsa 权限 0400

Step 2:工作空间与 Git 工具(P0-2, P0-3)

  • 实现 src/server/tools/workspace.py
  • 实现 src/server/tools/git_tools.py
  • 编写单元测试
  • 验收: 能 clone gitee 仓库,创建分支,commit+push

Step 3:SSH 工具与 API 路由(P0-4, P0-5)

  • 实现 src/server/tools/ssh_tools.py
  • 在 api_server.py 注册 /git/* 和 /ssh/exec 路由
  • 验收: HTTP 调用 clone + ssh exec 全流程通

Step 4:部署工具与完整流程(P1-1 ~ P1-3)

  • 实现 src/server/tools/deploy_tools.py
  • 注册 /deploy/k8s 路由
  • 配置 RBAC
  • 验收: 调用 /deploy/k8s 触发滚动更新成功

Step 5:MCP 工具注册与增强(P1-4 ~ P1-6, P2)

  • 在 mcp_server.py 注册新工具
  • workspace 管理端点
  • 按需推进 P2 优化项

成功标准

  1. 完整工作流(clone → branch → 代码修改 → commit/push → SSH 测试 → K8s 部署)可通过 HTTP API 驱动,无人工干预
  2. 所有凭证(git token、SSH 私钥)通过 K8s Secret 注入,不硬编码
  3. 并发多任务互不干扰(task_id 隔离)
  4. 单个操作失败有明确错误信息,不影响其他任务
  5. Pod 重启后工作空间可按需重建(无状态设计)

Does this plan capture your intent?

  • proceed — 开始实现,移交 executor
  • adjust [X] — 返回调整某个模块设计
  • restart — 废弃重新开始