Commit Graph

5 Commits

Author SHA1 Message Date
Chiguyong 04ad5966d0 fix(enterprise): ce-debug P3 residual batch — SEC-2 OIDC 验签 + STAND-3 SCIM /scim/v2 + MIG-2 schema 迁移
Test / backend-test (pull_request) Waiting to run Details
Test / frontend-unit (pull_request) Waiting to run Details
Test / api-e2e (pull_request) Waiting to run Details
Test / frontend-e2e (pull_request) Waiting to run Details
13 项 P3 residual findings 全部清零:

安全/合规
- SEC-2: OIDC id_token 用 JWKS 验签 + IDToken claims_cls 校验 iss/aud/exp(fail-closed,无 jwks_uri 时拒绝回退)
- STAND-3: SCIM router 改挂 /scim/v2(RFC 7644 标准路径)+ 修复双重前缀 bug(router 内部 prefix 移除,由挂载点控制)
- API-12/14: SCIM PATCH 严格性 — 不支持的 op/path 返回 400 noTarget + path==None 时遍历 value keys

性能/可观测
- PERF-6/7: gateway cache metric 修正 — None usage 早退 + 仅对 anthropic/claude model 记录 cache hit/miss

部署/运维
- DEPLOY-8: key-rotation-runbook 拆分 Slot 10(Redis)/Slot 11(PostgreSQL)
- DEPLOY-9: Helm chart 支持 image.digest pinning(@sha256:<digest> 覆盖 tag)

迁移/维护
- MIG-2: auth DB schema 迁移注册表(_SCHEMA_MIGRATIONS dict + _run_schema_migrations 按 version 差值执行)
- MAINT-2: bitable delete_view 三态错误信息(不存在 vs 最后一视图 vs 并发竞争)
- MAINT-3: chatStream 提取 findStreamingSynthesisMilestone helper(去重 team_synthesis_chunk/team_synthesis 谓词)
- MAINT-4 + STAND-2: 前端测试 token 正则 helper + replace 加 g 标志(移除所有 :root 块)

验证:ruff check + format(P3 文件全过)| pytest 526 passed(calendar webhook SSRF 失败为 pre-existing)| helm lint 通过
2026-07-06 12:18:42 +08:00
Chiguyong cb278bb5f0 fix(enterprise): ce-debug batch — PERF-1 PII filter + DEPLOY-1/2/4/5 + SCIM RFC 7643/7644
Test / backend-test (pull_request) Waiting to run Details
Test / frontend-unit (pull_request) Waiting to run Details
Test / api-e2e (pull_request) Waiting to run Details
Test / frontend-e2e (pull_request) Waiting to run Details
修复 ce-code-review 发现的全部 P1/P2 residual findings:

P1:
- PERF-1: PII 脱敏接入 gateway chat()/chat_stream() 生产路径
  (env AGENTKIT_PII_FILTER_ENABLED=true 启用,fail-closed)
- API-1/2/5/6/7/9/11/13 + STAND-1 + SEC-3: SCIM router 全面重写
  - API-1: totalResults 用 SELECT COUNT(*) 返回全量总数
  - API-2: 异常处理器转 RFC 7644 错误格式(scope 到 /scim/v2)
  - API-5: create_user 写 user_idp_links(idp_name='scim')
  - API-6: POST /Users 返回 Location 头
  - API-7: PATCH userName UNIQUE 冲突 → 409
  - API-9: 不支持的 filter → 400 invalidFilter
  - API-11: displayName=None
  - API-13: filter 大小写不敏感
  - STAND-1: dict[str, Any] → dict[str, object]
  - SEC-3: active true→false 写审计(延后到事务提交后避免 SQLite 锁竞争)
- API-4: _sso_issue_token_pair 用 secrets.token_urlsafe(32) 生成真实 refresh_token
  (移除 __pending_sso__ 占位符 + 后续 UPDATE 的非原子两步写入)
- API-8: _sso_issue_token_pair 增加 provider_type/provider_name 参数
- API-10: deprovision_user/change_user_role 加 response_model
- DEPLOY-1: install.sh + docs 用 instance 标签选择器替代硬编码 fullname
- DEPLOY-2: 11 处 Redis 客户端构造显式传入 REDIS_PASSWORD env var

P2:
- DEPLOY-4: 移除 agentkit deployment 中死 env POSTGRES_PASSWORD
  (应用通过 DATABASE_URL Slot 3 内嵌密码连接,不读此 env)
- DEPLOY-5: OTel token 格式改为 Authorization=Bearer <token>
  (符合 OTEL_EXPORTER_OTLP_HEADERS key=value 规范)

测试:
- ruff check + format 全部通过
- pytest tests/unit/test_scim_router.py 9 passed
- pytest tests/unit/test_llm_gateway.py + test_handoff.py + test_event_queue_integration.py 70 passed, 5 skipped
- helm lint + helm template 验证 POSTGRES_PASSWORD env 已移除
2026-07-06 11:41:06 +08:00
Chiguyong 3cf29f4633 fix(enterprise): ce-code-review P1 fixes — SSO is_active + span leak + Helm chart integration
Stage 5c applied safe P1/P2/P3 fixes from multi-agent code review:

- SEC-1 (P1, security): SSO 登录绕过 is_active 检查 — _sso_issue_token_pair
  入口加显式校验,与本地 login(auth.py:377)一致。已停用用户无法再通过
  IDP 回调拿 JWT,封堵 R1b deprovisioning 绕过。

- PERF-2/3 (P2, reliability): gateway chat() span 泄漏 + 异常未记录 — try 块
  扩展到覆盖整个 span 生命周期(含 cache 设置),新增 except 分支调用
  record_exception + set_status(ERROR),失败调用在 trace 中不再显示为成功。

- API-3 (P1, test isolation): SCIM router 使用 import-time 捕获的
  DEFAULT_AUTH_DB_PATH — 改为 resolve_auth_db_path() 在调用时读取 env var,
  让测试 monkeypatch.setenv 可见。

- MAINT-1 (P3, dead code): 删除 BitableRepository.delete_view(被
  delete_view_if_not_last 取代,无生产调用方,仅 docs 残留引用)。

- PERF-4/5 (P3, performance): pii_filter._record_pii_metrics 的 from import
  提升至模块顶部 + except: pass 改为 logger.debug 记录失败原因。

- DEPLOY-3 (P1, chart integration): ConfigMap 不可达 — deployment.yaml
  args 增加 --config /etc/agentkit/agentkit.yaml,让应用能加载 chart 渲染
  的非密配置。

- DEPLOY-6/7 (P3, doc/chart consistency): values.yaml 注释残留旧 slot 名
  redisPgPasswords → redisPassword;slot 计数 10 → 11(5 处 chart + 3 处
  deployment docs 同步修正)。

Verification:
- ruff check + format clean (7 modified .py files)
- pytest tests/unit/{auth,bitable} + test_{pii_filter,oidc_provider,
  saml_provider,scim_router,auth_audit,telemetry,prompt_cache_layers}.py
  → 336 passed, 145 skipped
- helm lint + helm template 验证 secret key 一致性

Residual findings (deferred to follow-up):
- PERF-1: PII filter 未接入 gateway 生产路径(manual, 需配置接入决策)
- API-1/2/4/5: SCIM RFC 7644 合规性(totalResults/error format/Location
  header/SSO 预配联动)— manual, 需设计决策
- DEPLOY-1/2/4: Helm chart ↔ app 集成断裂(部署名引用/Redis 鉴权/PG 密码双源)
  — manual, 需 app+chart 联动修改
2026-07-06 08:36:59 +08:00
Chiguyong 86bce129a4 refactor(enterprise): simplify U1-U6 — fix span leak, dedup helpers, stdlib parsing
lfg Step 3 (ce-simplify-code) — 16 files, -89 net lines.

P1 fixes (functional):
- audit.py / scim/router.py: fix OTel span leak — start_span() returned a
  context manager but was used as a plain object, so spans never ended
  and never exported. Wrap in `with`.
- helm chart: split combined `redisPgPasswords` slot (single JSON key)
  into `redisPassword` + `postgresPassword` slots — the combined `key`
  field was dead config never referenced by any template; deployment.yaml
  hardcoded `redis-password`/`postgres-password` keys were inconsistent
  with values.yaml schema.

P2 dedup (reuse):
- Promote `resolve_auth_db_path()` to models.py (canonical); remove 3
  duplicate `_resolve_db_path` defs in oidc.py / saml.py / audit.py.
- Reuse `_now_iso` from models.py; remove 5 duplicates across audit /
  oidc / saml / scim / local providers.
- Reuse `_row_to_user` from local.py in oidc.py / saml.py (verbatim
  copies removed).
- pii_filter._redact: collapse redundant `finditer` + `sub` (2 regex
  passes + 2x sha256 per match on hot path) into a single `sub` with a
  callback that collects matches and computes hashes once.

P3 simplifications:
- RoleChangeRequest.role: `str` + manual `if not in (...)` → `Literal`
  (Pydantic validates automatically).
- Extract `_record_pii_metrics(status, redacted_count)` helper to dedup
  3 nearly-identical OTel metric emission blocks.
- Extract `LLMGateway._record_prompt_cache_metric(usage, model)` to dedup
  non-stream + stream cache hit/miss counters; switch to use the
  `TokenUsage.cache_hit` property (previously added but unused).
- middleware: split `WHITELIST_PATHS` + `PREFIX_MATCH_PATHS` (redundant
  cross-reference) into `WHITELIST_PATHS` (exact) + `PREFIX_WHITELIST_PATHS`
  (prefix) — single source of truth per kind.
- OIDC token exchange: replace f-string form body with `urlencode` to
  correctly escape `&` / `=` in code / redirect_uri.
- auth.py OIDC redirect route: replace hand-rolled `url.split("state=")`
  with `urlparse + parse_qs`.
- PII module docstring: clarify that `PIIMatch.original` is in-memory
  only (must not be logged / persisted) — the previous "仅 hash, 不含
  原文" wording was misleading.

Skipped findings (false-positive or not worth):
- OIDC/SAML `_find_or_create_user` JIT 60-line dedup — high blast
  radius across SQL + transaction boundaries; defers to dedicated refactor.
- SAML `_extract_host` hand-rolled split — already has ponytail comment;
  stdlib `urlparse` swap is behavior-equivalent for current inputs but
  changes OneLogin `http_host` field semantics; conservative keep.
- gateway.py department-quota / usage-record sequential await —
  concurrency gain unclear when dept count is typically ≤2.

Verification:
- ruff check (scoped to 12 touched files) clean
- ruff format (1 file reformatted)
- pytest (PII + OIDC + SAML + SCIM + audit + bitable + team_orchestrator):
  265 passed, 145 skipped (PG/Docker), 0 failures
- helm lint clean; helm template renders correctly for both
  sealed-secrets + external-secrets backends
2026-07-06 08:02:40 +08:00
Chiguyong af9cb9496c feat(deploy): U5 — K8s Helm Chart + Sealed Secrets + 离线安装包
U5 产出政企生产级 K8s 部署 artifacts:

Helm Chart — deploy/helm/agentkit/ 含 Chart.yaml + values.yaml +
8 个 templates(deployment/service/ingress/configmap/sealed-secret/
external-secret/serviceaccount/_helpers)。

values.yaml 显式列出 10 个 secret slot(KTD-4):JWT 签名密钥 /
API Key / DB 凭据 / IDP 签名证书 / 第三方 API Key / TLS 服务器证书 /
mTLS 客户端证书 / KMS-HSM PIN / OTel exporter token / Redis-PG 密码。

Sealed Secrets + External Secrets Operator 双模板,禁用 plain
Kubernetes Secret + Git 提交。serviceaccount 配置 projected token
注入支持 KMS/HSM workload identity。

离线安装包 — build-images.sh 构建镜像 tarball +
package-chart.sh 打包 chart tarball + install.sh 离线安装,
覆盖原生 K8s 1.28+ / Helm 3.x。

运维文档 — k8s-install.md 部署指南 + key-rotation-runbook.md
密钥轮换 runbook(10 slot)+ secret-inventory.md 密钥清单。
2026-07-06 07:21:41 +08:00