Commit Graph
162 Commits
Author SHA1 Message Date
chenchenandClaude Opus 4.8 b754af8ba1 fix(mcp-server): device-code 一次性作废失效修复(consume 集群 Redis 删除未生效)
初版 consume_device_code 用裸 redis_client.delete() 且吞异常,在集群 Azure
Redis 上删除未生效,导致一个 device_code 换发 token 后仍能在每次 >interval
的轮询继续换发新 token —— 违反 RFC 8628 一次性语义与验收「换一次后再用→拒绝」。

初测二次轮询都在 slow_down 窗口内(<5s)被限流响应遮住,未暴露;>5s 公网
真实轮询复测才暴露。

修复:consume 改用已验证可靠的 _set_keepttl 置 status=consumed(token 端点
签发前硬检查 consumed → expired_token),并 best-effort 删除 device_code +
device_user_code 两个 key。即使集群删除失败,状态位硬拦截。

复测(公网 APIM 真实路径,间隔 >5s):首 poll 签发 → 二/三次 poll 均
expired_token,不再重复签发。

镜像 device-code-fix2-20260722-arm64 @sha256:716c2e2d 已部署生产 3/3 Running。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 15:24:27 +08:00
chenchenandClaude Opus 4.8 f5f0218233 feat(mcp-server): headless 设备登录 device-code(RFC8628) authorize/approve/token 端点
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:16:03 +08:00
chenchenandClaude Opus 4.8 448401427f feat(mcp-server): 企业邀请 org-invite-email 端点 + magic-link landing web 模式(Q2-B)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:30:21 +08:00
chenchenandClaude Opus 4.8 8a07edecd8 feat(mcp-server): 企业邀请预开通端点 /api/auth/internal/provision + email 小写归一化(Q3)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:54:22 +08:00
chenchen 697ea5ac7b bak 2026-06-24 18:01:46 +08:00
chenchenandClaude Opus 4.8 c343525959 docs(heicode): §21-§24 #19 收口 + 开闸 + HM#74 落地域名改 code.heicode.cc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 15:32:22 +08:00
chenchenandClaude Opus 4.8 75f78c59c6 chore(k8s): 发信切 Gmail(super@heicode.cc) + 开启发信总闸 + 落地域名改 code.heicode.cc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 15:32:21 +08:00
chenchenandClaude Opus 4.8 8f3b25f491 chore(k8s): prod 注入 MAGIC_LINK_EMAIL_ENABLED + 镜像 tag 升 arm64-v2
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 16:26:45 +08:00
chenchenandClaude Opus 4.8 e01396ba4d docs(heicode): §16-§20 端到端全通 + ① APIM 验掉 + D-5 发信收口
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 16:26:44 +08:00
chenchenandClaude Opus 4.8 874dbda969 docs(heicode): §15 mcp→HM 可开始 request/verify 联调 + 联调期发信选型(A/B)
直接在共享文件答复 HM:request/verify 已上生产可联调;landing 的 ① APIM
透传我方跟进;需 HM 回 §15.3 一句——联调期发信走临时开真发(A)还是 mock 取链接(B)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:36:56 +08:00
chenchenandClaude Opus 4.8 cb280e6758 docs(heicode): §14.4 magic-link 三端点已部署生产 + 联调指引
记录已上线 taiji-ai 生产、集群内实测通过、发信总闸=mock;HM 可即刻就
request/verify 联调,landing 仍待 ① APIM heicode:// 302 透传确认。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:04:17 +08:00
chenchenandClaude Opus 4.8 58cc652210 feat(mcp-server): magic-link 增加 MAGIC_LINK_EMAIL_ENABLED 发信总闸(默认 mock)
契约 §13.2「D-5 签字前默认不外发」。即便生产已配 SMTP_PASSWORD,未置 true 前
一律 mock(打日志不外发),防止公网可达端点被滥用对真实用户发信。敏感链接仅
DEBUG 下打印(§1.4 不在普通日志留存凭证)。签字后运维置 MAGIC_LINK_EMAIL_ENABLED=true。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 19:23:49 +08:00
chenchenandClaude Opus 4.8 b44a1f9ee6 chore(k8s): prod 注入 MAGIC_LINK_PUBLIC_BASE_URL + 升级 mcp-server 镜像 tag
- configmap.yaml:新增 MAGIC_LINK_PUBLIC_BASE_URL=APIM 域(§11 终态)
- mcp-server.yaml:引用该 env + 镜像升至 magic-link-20260609

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:26:21 +08:00
chenchenandClaude Opus 4.8 66423c0845 feat(mcp-server): Heicode magic-link 邮箱登录三端点(仅登录,不触碰自有登录)
按 Docs/Heicode-magic-link…md 契约 §7.4/§9.4/§11/§13.2 新增并行登录方式:
- app/magic_link.py:Redis 一次性 token(600s)/code(120s) + 邮箱60s限流 + 复用
  现有 SMTP 通道发链接邮件(SMTP_PASSWORD 未配则不外发,DEBUG 打日志)
- app/routes/auth.py:新增 /api/auth/magic-link/{request,landing,verify}
  · request:IP+邮箱限流,防枚举一视同仁,仅对已存在 role=user 发信(D-1/D-2/D-3)
  · landing:消费 token→生成 code→302 heicode://auth/callback,失败回 HTML
  · verify:消费 code→复用 create_access_token/refresh + 与 /login 逐字段相同
    token_data → 登录产物等价,EU/计费零改动(§1.3)
- config.py:新增 MAGIC_LINK_PUBLIC_BASE_URL(默认 APIM 域,§11 终态)
- 三端点不声明 Depends(require_auth) 即公开,未改 allow_paths(§12.2)
- /login、/me、/refresh、/logout、/register 一行未改

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:25:02 +08:00
chenchenandClaude Opus 4.7 2477d01d61 docs(heicode): §7.17 ack token rotation + answer email-lookup question
Heicode rotated NewAPI service token (fingerprint 25b85d67…b1d6) per §7.16.7.
Walked through §7.7.2.1 flow:
  1. Read Docs/heicode-svc-token.txt — fingerprint matched
  2. kubectl create secret generic heicode-newapi (key=service-token)
  3. rollout restart — completed
  4. P4 smoke 4/4 with 55@55.com — balance/models/usage/logs all 200
  5. Deleted local Docs/heicode-svc-token.txt
  6. This §7.17 ack

Answer to Heicode's lookup question:
  Their `zsbgnw@gmail.com → USER_NOT_FOUND` observation was a side-effect of
  the stale token: while their new token was staged but our k8s secret still
  held the previous value, every NewAPI call returned 401, and our
  resolve_user_id_by_email() catches HeicodeNewAPIError and returns None —
  which the P4 router translates to 404 HEICODE_USER_NOT_FOUND.

  Direct re-test from inside the pod after rotation:
  `GET /api/user/search?keyword=zsbgnw@gmail.com&group=` → 200, 1 item,
  id=22 email=zsbgnw@gmail.com username=chenchen. Our query path is exactly
  what they suggested (`/api/user/search` with empty `group`), and we filter
  by email field downstream — implementation is fine.

Bonus finding: post-rotation `/balance` for zsbgnw@gmail.com returns
502 HEICODE_NEWAPI_UPSTREAM_ERROR because user 22 is super-admin and our
admin token holder (user 26) cannot read same-or-higher-level users
("No permission to access users of same or higher level"). NewAPI returns
HTTP 200 with success=false, our client correctly raises HeicodeNewAPIError.
This is an authorization policy on their side, not a bug — three options
proposed in §7.17.3 for product decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:58:37 +08:00
chenchenandClaude Opus 4.7 267172e103 fix(mcp-server): two audit-found register bugs
Found by post-fix audit pass over this session's changes:

1. Predcheck used `effective_username = (req.username or "").strip()` but the
   write at the User() construction site still used `req.username` raw. If a
   client sent "alice " with trailing whitespace, predcheck queried for "alice"
   (clean), missed the conflict, then wrote "alice " back. Now both sites use
   the same `effective_username` value — single source of truth.

2. Post-commit `verify_code` was guarded by `except Exception`, but
   `asyncio.CancelledError` is a BaseException and propagates through. If the
   request task is cancelled (client disconnect / pod shutdown) after DB
   commit but before verify_code finishes, the verification code stays in
   Redis with full 10-min TTL. Wrapped with `asyncio.shield(...)` so
   verify_code completes regardless of cancellation, and an explicit
   `except CancelledError: raise` preserves FastAPI's cancellation semantics
   for the outer request.

Verified via smoke:
- Register with username "ws_user_$ts  " (trailing spaces) → DB stores
  "ws_user_$ts" (18 chars, no whitespace). Predcheck and write now agree.
- P4 透传 (balance/models/usage/logs via 55@55.com) still 4/4 — no regression.

Latent bug noticed but NOT introduced this session, deferred:
- auth.py:981 writes ResourceAllocation.resource_id=str(provider.id) for
  model allocations, but channel.py:1881 queries by resource_id==model_name.
  Pre-existing inconsistency means update_tenant_model_quota never finds
  rows created at register time. TenantModelKey row is still updated
  correctly so end-user quota is honored; only the ResourceAllocation
  audit/reporting view diverges. Fix requires deciding which side is
  canonical — out of scope for security hardening.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:09:55 +08:00
chenchenandClaude Opus 4.7 1461051755 fix(mcp-server): correct Heicode user-models endpoint + username predcheck
Two small follow-ups to the register hardening + Heicode P4 work:

1. heicode_client.list_user_models: the path `/api/user/{id}/models`
   prescribed in §7.11.2 returns 404 `Invalid URL` on the live Heicode
   NewAPI — that path is not registered on their router. Switched to
   `/api/user/models` (no path segment), which Heicode binds to the
   `New-Api-User: 26` admin header. End-to-end P4 smoke now 4/4 with
   user 55@55.com (id=2 on Heicode): /balance /models /usage /logs.
   Future: if Heicode ships an "admin-replaces-user" path, switch back
   and pass the actual heicode_user_id.

2. routes/auth.register: previously line-744 SELECT only checked
   req.username, but line 778 falls back to email.split("@")[0] when
   blank — so two users registering with alice@foo.com and alice@bar.com
   would both clear the predcheck, then the second would IntegrityError
   on flush. Now predcheck uses `effective_username` matching what'll
   actually be inserted.

Also append §7.15 to Heicode-对接进度与待办.md:
- 4-item agent-manager / Vault / Workload-Identity audit results
- §7.13 token rotation acknowledgement
- P4 end-to-end first-pass results
- This-session internal security hardening summary

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:50:20 +08:00
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
chenchenandClaude Opus 4.7 eb17ed84f8 fix(mcp-server): plug LiteLLM API key leak via register & tenant model assignment errors
A failed POST /api/auth/register returned the SQLAlchemy IntegrityError verbatim
to the caller, which included the full INSERT INTO tenant_model_keys statement
along with every bound parameter — ~50 plaintext LiteLLM API keys per failed
attempt. Same pattern was reproduced in 3 channel.py endpoints that wrap
LiteLLM key INSERTs.

Changes:
- channel.py: assign_resources_to_tenant / assign_model_to_tenant /
  update_tenant_model_quota — log full exc_info, return a typed
  {code, message} error instead of f"...{str(e)}". 6 leakage points sealed.
- email_verification.py: add peek_verification_code() — checks a code
  without burning it. Lets the register handler verify *before* the
  multi-step transaction so a downstream failure doesn't waste the user's
  one-shot code.
- scripts/cleanup_orphan_litellm_keys.py: one-shot orphan key reaper.
  Scans LiteLLM /key/list by metadata.tenant_id (plus a manual list of
  the 8 publicly-leaked sk- prefixes from the original incident).
  Used to nuke 16 orphan keys for tenant fab9dc27-… on 2026-05-12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:42:38 +08:00
chenchen 46a3da0eb4 更新md 2026-05-05 14:25:28 +08:00
chenchen d0b79030f1 更新heicode 2026-05-05 14:13:59 +08:00
unknown 3692b165a0 更新备份 2026-03-25 21:34:44 +08:00
unknown e379f9dee6 备份 2026-03-25 20:48:00 +08:00
zhanggangyong 40447f86f6 更新开发者平台 2026-03-16 04:05:44 +00:00
zhanggangyong a3d7ef6a6e 备份 2026-03-15 15:30:24 +00:00
zhanggangyong 648921b26c 生产备份 2026-03-13 02:53:27 +00:00
zhanggangyong 7ddac1bea7 计费备份 2026-03-12 02:32:23 +00:00
zhanggangyong a540e6d61a 更新计费 2026-03-10 06:40:38 +00:00
zhanggangyong 368198f53c 更新爆改前的备份 2026-02-09 06:40:04 +00:00
zhanggangyong a498072888 备份 2026-02-02 14:08:13 +00:00
zhanggangyong 1177f696f1 更新工具说明文档 2026-01-26 06:49:28 +00:00
zhanggangyong fe69a70a3a 更新外部数据工具和工具集 2026-01-23 10:57:13 +00:00
zhanggangyong d59dcfa941 geng 2026-01-22 03:32:09 +00:00
zhanggangyong 6d164c838b 更新大志备注 2026-01-16 10:38:17 +00:00
zhanggangyong 9ceb72abf1 更新yaml文件 2026-01-15 07:43:09 +00:00
zhanggangyong 114ddd4803 更新前备份 2026-01-15 03:59:03 +00:00
zhanggangyong 6ead42a050 更新停止agent文档 2026-01-14 14:11:20 +00:00
zhanggangyong 31ba6fb8f1 更新agent域名 2026-01-14 13:42:36 +00:00
zhanggangyong 72ed8c1d29 更新信息接口 2026-01-14 06:54:04 +00:00
zhanggangyong e17f38112b 更新信息接口 2026-01-14 06:37:39 +00:00
zhanggangyong 5b1c384764 更新agent DNS 2026-01-14 06:28:45 +00:00
zhanggangyong 8f86d22f00 更新信息查询 2026-01-13 13:36:41 +00:00
zhanggangyong 1b079ed870 更新自定agent的工具列表 2026-01-13 12:12:18 +00:00
zhanggangyong b165123bd9 更新计费余额不足时中止agent 2026-01-13 09:15:41 +00:00
zhanggangyong faf2c8afd3 更新前端模板 2026-01-13 05:07:06 +00:00
zhanggangyong 0ddc548d0f 更新超级管理查看资源分配 2026-01-12 17:16:55 +00:00
zhanggangyong c6bab43f12 更新渠道修改密码文档 2026-01-12 17:01:36 +00:00
zhanggangyong 1154b4e7ae 更新租户配额 2026-01-12 16:47:41 +00:00
zhanggangyong 3d5fd1f843 更新自由注册文档 2026-01-12 14:45:32 +00:00
zhanggangyong dd8c4c194d 更新自由注册邮箱验证 2026-01-12 14:43:14 +00:00