Files
taiji-AI-PAD/services/mcp-server/migrations/028_add_heicode_approvals.sql
T
chenchenandClaude Opus 4.7 610fde5d03 feat(mcp-server): Heicode integration + register transaction hardening
== Heicode integration (~41 endpoints across 5 modules) ==
- §2 ResourceBinding (5 endpoints) — resources.py / resource_grants.py
- §4 NewAPI metadata proxy (4 endpoints) — heicode_proxy.py + heicode_client.py
- §5 Agnet platform stub (12 endpoints, in-memory mock) — agnet_stub.py
- §6 Task orchestration (5 endpoints + 3 extension endpoints) — heicode_tasks.py
  6.1-6.5: intent / list / get / answer / messages
  6.6-6.8: execution / delivery / audit?tab=... (Slice 8/9/10)
- §7 SSE single channel + approvals (4 endpoints + 5 event types) —
  heicode_events.py + event_bus.py
- §7.8.1 internal billing-provider PUT endpoint — auth.py (routes)

== Schema changes ==
- migrations/026 heicode_tasks (orchestration state)
- migrations/027 users.billing_provider (litellm | newapi switch)
- migrations/028 heicode_approvals (high-risk approval queue)

== Register transaction hardening (P0 + P1 + P2) ==
routes/auth.py register():
- Pre-existing P0: failed register returned IntegrityError str verbatim
  (leaking SQL params + ~50 plaintext LiteLLM keys per attempt).
  Now logs exc_info, returns {code: REGISTER_FAILED, message: ...}.
- Pre-existing P0: model dedupe — two ModelProvider rows with overlapping
  supported_models (e.g. taiji/gpt-4o-mini in both taiji and azure providers)
  collide on uq_tenant_model. seen_models set deduplicates within the loop.
- New P1: track created_litellm_keys; on any failure call delete_key() for
  each — prevents remote orphan keys when DB rollback fires.
- New P1: replace verify_code with peek_verification_code at the start;
  only call verify_code (which consumes) after commit succeeds. Failed
  registrations no longer burn the user's one-shot code.
- New P2: narrow inner `except (LiteLLMClientError, Exception)` to just
  LiteLLMClientError so SQLAlchemy errors bubble to the outer rollback
  instead of being silently swallowed into a half-allocated 200 response.
- New P2: same narrowing on outer `except (AgentManagerError, Exception)`.

== Auth middleware ==
- app/auth.py: allow /api/auth/internal/billing-provider and
  /api/auth/internal/approvals to bypass user JWT (service-token auth
  via HEICODE_INTERNAL_SERVICE_TOKEN, validated in-route).

== Docs ==
- Heicode-接口契约文档.md v2.2 (41 endpoints + SSE schema + 6.6-6.8)
- Heicode-对接进度与待办.md (through §7.14 SSE + 7.8.2 delivery回执)
- Heicode-完整调用流程图.md (sequence + routing diagrams)
- Agent-Manager-Heicode对接需求文档.md
- HEICODE_API_INTEGRATION.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:43:10 +08:00

43 lines
2.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Migration 028: Heicode 高危审批表(§7.8.3 配套)
--
-- 高危操作(risk_level=high)部署 / 资源访问产生 approval 记录;用户在
-- cc-haha ApprovalDialog 选择 approve/reject 后落库;同时通过 SSE 单通道
-- 把 approval.requested / approval.resolved 推给所有当前用户在线的客户端。
--
-- 字段对齐 cc-haha/desktop/src/stores/approvalStore.ts:ApprovalRequest
CREATE TABLE IF NOT EXISTS heicode_approvals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
-- 谁需要决策这个审批
task_id UUID,
-- 关联任务(可空,如系统级审批);不加 FK 因为 task 可能由其他平台创建
task_name VARCHAR(255) NOT NULL,
operation TEXT NOT NULL,
target_resource VARCHAR(500) NOT NULL,
requesting_role VARCHAR(100) NOT NULL,
risk_level VARCHAR(16) NOT NULL DEFAULT 'high',
-- low | medium | high
impact_summary JSONB NOT NULL DEFAULT '[]'::jsonb,
-- string[]:弹窗显示的 bullet 列表
heicode_suggestion VARCHAR(16),
-- approve | reject | delegate
derives_short_lived_credential BOOLEAN NOT NULL DEFAULT false,
ttl_minutes INTEGER NOT NULL DEFAULT 60,
enqueued_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
decision VARCHAR(16),
-- approve | reject | expired(NULL = 待响应)
resolved_by UUID,
-- 谁做的决定(user_id);expired 时为 NULL
resolved_at TIMESTAMP WITH TIME ZONE,
-- BaseModel 框架字段(每张 ORM 表都需要)
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_heicode_approvals_user ON heicode_approvals(user_id);
CREATE INDEX IF NOT EXISTS idx_heicode_approvals_pending ON heicode_approvals(user_id, decision)
WHERE decision IS NULL;
CREATE INDEX IF NOT EXISTS idx_heicode_approvals_task ON heicode_approvals(task_id);
CREATE INDEX IF NOT EXISTS idx_heicode_approvals_enqueued ON heicode_approvals(enqueued_at);