Skip to content

feat(gateway): add enterprise control-plane integration - #90

Open
desertsurge wants to merge 9 commits into
astaxie:mainfrom
desertsurge:feat/aip-enterprise-integration
Open

feat(gateway): add enterprise control-plane integration#90
desertsurge wants to merge 9 commits into
astaxie:mainfrom
desertsurge:feat/aip-enterprise-integration

Conversation

@desertsurge

Copy link
Copy Markdown
Collaborator

Summary

Adds a token-authenticated enterprise integration surface so an external AIP control plane can synchronize tenant topology and manage per-principal model access keys while TokenHub remains the runtime authorization and model-discovery authority.

Related Issue

N/A

Changes

  • Backend: add idempotent integration event ingestion and reconciliation for tenants, organizations, principals, projects, and workloads.
  • Backend: add internal APIs for model/provider/route discovery, scoped model access key creation, listing, reveal, revocation, request logs, and usage reporting.
  • Backend: protect AIP-managed projects and keys from normal mutation paths, encrypt revealable key material at rest, and enforce tenant, principal, lifecycle, and request-id constraints.
  • Tests: add integration, infrastructure, model access key, request log, usage, and multi-instance coverage.
  • Deployment and documentation: add TOKENHUB_INTEGRATION_TOKEN to environment examples, Compose definitions, install scripts, startup validation, and English, Simplified Chinese, and Japanese deployment guides.
  • Frontend and SDK: no feature-specific changes.

Type of Change

  • Bug fix
  • New feature
  • Refactor or maintenance
  • Documentation
  • Deployment or configuration

Verification

  • Backend: gofmt on changed Go files, go test ./..., and go vet ./...
  • Frontend: npm run typecheck and npm run build
  • SDK smoke tests against a compatible backend
  • Docker Compose configuration rendered successfully
  • Other focused or manual verification described below

Verification details:

  • PASS: resolved the merge against current main; the branch is 0 commits behind and git diff --check origin/main...HEAD passes.
  • PASS: formatted the conflict-resolved Go files and reviewed the 25-file PR diff against current main.
  • PASS: frontend/node_modules/.bin/tsc.cmd --noEmit and npm run build.
  • BLOCKED: go test ./... downloaded Go 1.26 successfully but this Windows host has CGO_ENABLED=0 and no GCC/Clang. Compilation stops at the existing origin/main SQLite backup call (store.go: dest.Backup undefined). go vet ./... is blocked by the same environment limitation.
  • BASELINE FAILURE: npm run typecheck reaches the source-line check and reports three files already unchanged from origin/main above the 1,500-line limit: features/admin/i18n/en.tsx, features/admin/i18n/ja.tsx, and features/admin/views/provider-editor.tsx. Direct TypeScript compilation passes.
  • NOT RUN: SDK smoke tests require a compatible running backend and provider credentials.
  • NOT RUN: Docker Compose rendering because Docker Desktop is not running on this host.

Compatibility, Security, and Operations

  • OpenAI-compatible /v1 API impact: No intentional contract changes. The new endpoints are under /api/internal; AIP-managed keys authenticate through the existing gateway path.
  • Security or credential-handling impact: Adds a dedicated TOKENHUB_INTEGRATION_TOKEN. Model access secrets are returned only by create/reveal operations, stored encrypted at rest, excluded from public serialization, and constrained by tenant, principal, status, expiry, and idempotency rules.
  • Database, environment, or deployment impact: Adds control-plane synchronization tables and additive API key fields through AutoMigrate. Deployments must configure a strong integration token; examples, Compose files, startup scripts, validation, and deployment guides are synchronized.
  • Rollout and rollback considerations: Configure and rotate the integration token before enabling AIP traffic. Roll back by stopping AIP calls and deploying the previous binary; additive database columns/tables can remain without affecting existing /v1 traffic.

Checklist

  • Tests were added or updated for behavior changes, or the reason they are unnecessary is documented.
  • No credentials, local .env files, databases, backups, or runtime logs are included.
  • Environment variable changes are synchronized across examples, Compose, start.sh, and deployment documentation where applicable.
  • Shared user-facing behavior is documented consistently in English, Simplified Chinese, and Japanese where applicable.
  • data/model-catalog.yaml remains tracked and catalog changes were reviewed where applicable.
  • git diff --check passes.

@astaxie astaxie left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary / 审查总结

中文

本次审查发现 3 个阻塞问题和 3 个需要补齐或澄清的需求问题。下方已添加 5 条行内评论;另有 1 个无法锚定到 diff 的阻塞问题:

  • [P1] 原生安装与升级会启动失败。 backend/internal/server/config.go 现在要求生产环境必须提供强 TOKENHUB_INTEGRATION_TOKEN,但 deploy/native/install.shwrite_initial_config 没有生成或写入该变量。新安装会回退到 dev_integration_token 并被启动校验拒绝;升级会保留缺少该变量的旧配置,结果相同。请为新安装生成独立 Token,为已有配置增加升级迁移,并在 deploy/native/install_test.sh 覆盖这两条路径。

验证结果:go test ./...go vet ./...、Gateway 定向测试和 git diff --check 均通过;项目覆盖、跨租户 usage 关联和过期后幂等重放问题均已通过未提交的最小测试复现。

English

This review found three blocking issues and three requirements that need implementation or clarification. Five findings are attached inline. One blocking issue cannot be anchored to the diff:

  • [P1] Native installs and upgrades will fail to start. backend/internal/server/config.go now requires a strong TOKENHUB_INTEGRATION_TOKEN in production, but write_initial_config in deploy/native/install.sh neither generates nor writes it. Fresh installs fall back to dev_integration_token and fail startup validation; upgrades preserve older config files without the variable and fail the same way. Please generate a separate token for fresh installs, migrate existing configs during upgrade, and cover both paths in deploy/native/install_test.sh.

Validation: go test ./..., go vet ./..., focused Gateway tests, and git diff --check pass. The managed-project overwrite, cross-tenant usage join, and post-expiry idempotency issues were also reproduced with uncommitted minimal tests.

This is a COMMENT review and does not change the PR approval state.

Comment thread backend/internal/server/store.go Outdated
Comment thread backend/internal/server/gateway_request_logs.go Outdated
Comment thread backend/internal/server/gateway_model_access_keys.go
Comment thread backend/internal/server/gateway_model_access_keys.go
Comment thread backend/internal/server/gateway_integration.go
@desertsurge

Copy link
Copy Markdown
Collaborator Author

本轮审查问题已在 cb78ae0e80d187 全部修复。

无法锚定的原生安装问题也已处理:新安装会生成独立的 32-byte TOKENHUB_INTEGRATION_TOKEN,升级旧配置时仅在缺失时补写,后续升级不会覆盖已有值,也不会复用 Admin Token。deploy/native/install_test.sh 已覆盖新安装、旧配置迁移和保留已有 Token。

验证结果:当前提交 e80d187 的 Backend、Frontend、Deployment 三项 GitHub Actions 均通过;本地安装器集成测试、TypeScript 编译、Next.js 生产构建和 git diff --check 通过。

# Conflicts:
#	backend/internal/server/types.go
#	docs/deployment.md
#	docs/ja/deployment.md
#	docs/zh-CN/deployment.md
@astaxie

astaxie commented Aug 1, 2026

Copy link
Copy Markdown
Owner

因为老文件进行了大量的重构,需要解决冲突问题

# Conflicts:
#	backend/internal/server/config.go
#	backend/internal/server/http.go
#	backend/internal/server/store.go
#	backend/internal/server/types.go
#	start.sh

@astaxie astaxie left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审确认原先 6 项问题中 5 项已完整修复;组织生命周期仍有一处列表状态不一致,另外 Compose JSON fallback 还存在 Integration Token 丢失问题。下面两条需要继续修复。本 review 仅提交评论,不改变 PR 的审批状态。

return GatewayModelAccessKeyCreateResult{Key: publicKey(key), Secret: rawSecret, Created: true}, nil
}

const gatewayModelAccessKeyEffectiveStatusExpression = `(CASE

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 将组织生命周期纳入列表的有效状态

创建与运行时认证现在会检查项目所属组织以及用户的组织成员关系,但这里的 SQL 状态表达式和下面的批量状态计算仍只检查 tenant、project、principal/workload。组织停用或成员被移除后,Key 已经无法认证,却仍会在列表中返回为 activestatus=active 会错误包含它,status=disabled 会错误遗漏它,total 和分页也会随之不准确。我用最小回归测试复现了这一点。请让 SQL 筛选和批量 hydrator 使用与运行时认证相同的组织/成员规则,并补充列表及状态筛选测试。

Comment thread deploy/install.sh
case "$line" in
TOKENHUB_ENV=*) tokenhub_environment="${line#*=}" ;;
TOKENHUB_ADMIN_TOKEN=*) admin_token="${line#*=}" ;;
TOKENHUB_INTEGRATION_TOKEN=*) integration_token="${line#*=}" ;;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 在 Compose JSON fallback 中保留 Integration Token

这里新增的解析分支依赖 compose_environment 包含 TOKENHUB_INTEGRATION_TOKEN,但当 docker compose config --environment 不可用、脚本转而使用 config --format json 时,上面的 Python fallback 变量列表没有输出该变量。即使 JSON 中已有正确的强 Token,后续也会回退成 change-me-tokenhub-integration-token 并被生产校验拒绝,导致该兼容路径下的 --check-only 和安装始终失败。请把 Integration Token 加入 fallback 列表,并增加“--environment 失败但 JSON 成功”的安装脚本测试。

@astaxie astaxie left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本轮复审发现 4 个新的实现问题,已分别添加行内评论。此前两条未解决评论(组织生命周期未进入 Key 列表有效状态、Compose JSON fallback 丢失 Integration Token)在当前 c94ee63 中仍然有效,因此没有重复留言。

验证:go test ./...go vet ./...、两套安装器测试、Compose 渲染、repository gates 和 git diff --check 均通过;GitHub CI 也为绿色。本 review 仅提交评论,不改变 PR 审批状态。

KeySuffix: suffix,
Allowed: normalized.AllowedModels,
IPAllowlist: normalized.IPAllowlist,
Limits: normalized.Limits,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 将分钟限额写入当前准入逻辑读取的字段

Integration API 接受 limits.rate_limit_rpmlimits.token_limit_tpm,但这里仅把它们写入嵌入的 APIKey.Limits。当前请求准入路径在 store_routing_calls.go 中会先把这两个嵌入字段清零,再只读取独立的 APIKey.RateLimitRPM / TokenLimitTPM 指针,因此 AIP 创建 limits: {"rate_limit_rpm": 1} 的 Key 实际仍可无限请求。请把这两个值映射到当前规范字段(并明确 0/未设置语义)、校验非负值,并补充第二个分钟内请求被拒绝的回归测试。

if err := tx.Save(&item).Error; err != nil {
return "", "project", 0, "", err
}
if err := syncGatewayServingProject(tx, item, now); err != nil {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 删除项目时永久吊销已有 Key

project.archivedproject.deleted 目前都只会把 serving Project 设为 disabled;这里没有像 tenant、organization、workload 删除那样吊销项目下的 Key。之后若同一 external project 收到更高版本的 project.updated 且状态恢复 active,projectionStatus 会清除 DeletedAt,旧 Key 也会重新通过运行时 scope 校验。Archive 已经提供可恢复语义,Delete 不应让已删除项目的旧凭据在重建后复活。请仅在 project.deleted 时永久 revoke 项目下的托管 Key,并覆盖 delete → recreate 后旧 secret 仍不可用的测试。

offset := time.Duration(filter.TimezoneOffsetMinutes) * time.Minute
dateFrom := filter.DateFrom.Add(offset)
dateTo := filter.DateTo.Add(offset)
for date := dateFrom; !date.After(dateTo); date = date.AddDate(0, 0, 1) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 按日历日期而不是具体时刻补齐 timeseries

这里从 date_from 的具体时刻开始逐日递增,并用完整时间与 date_to 比较。例如查询 7/27 12:00 到 7/28 10:00 时,SQL 汇总和 breakdown 会包含 7/28 上午的数据,但循环下一步是 7/28 12:00,因超过结束时间而完全漏掉 7/28 的 timeseries bucket。请先在请求时区偏移下把两端归一化为日历日期,再按日期闭区间迭代,并增加跨天但非整日的回归测试。

if reason := weakProductionSecretReason(c.AdminToken, 32, "dev_admin_token", "change-me-tokenhub-admin-token"); reason != "" {
invalid = append(invalid, "TOKENHUB_ADMIN_TOKEN "+reason)
}
if reason := weakProductionSecretReason(c.IntegrationToken, 32, "dev_integration_token", "change-me-tokenhub-integration-token"); reason != "" {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 在生产配置中拒绝复用 Admin Token

PR 和部署文档都把 TOKENHUB_INTEGRATION_TOKEN 定义为专用凭证,并明确不能由 Admin Token 替代;但启动校验只分别检查长度和占位值,同一个 32 字节字符串同时配置给 Admin 与 Integration 仍会通过。这样 Admin Token 就可以调用拓扑写入以及 Key reveal/revoke 接口,实际消除了两个权限面的隔离。请在后端启动校验和部署脚本校验中拒绝两个 Token 相等,并补对应测试。

@astaxie astaxie left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of current head 1da32c4: this is not merge-ready. The only changes since reviewed head c94ee63 are the merge from upstream main; none of the six files called out in the previous review changed. The organization lifecycle list status, Compose JSON fallback token, canonical RPM/TPM fields, permanent project-delete revocation, calendar-date timeseries fill, and Admin/Integration token separation findings therefore all remain actionable. Green CI confirms the merged tree builds, but does not resolve those behavior gaps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants