Skip to content

Relax token key column length for legacy migration compatibility - #4401

Merged
Calcium-Ion merged 4 commits into
QuantumNous:mainfrom
XiaoAI1024:codex/legacy-token-key-compat
Apr 23, 2026
Merged

Relax token key column length for legacy migration compatibility#4401
Calcium-Ion merged 4 commits into
QuantumNous:mainfrom
XiaoAI1024:codex/legacy-token-key-compat

Conversation

@XiaoAI1024

@XiaoAI1024 XiaoAI1024 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

model.Token.Key 的数据库列类型从 char(48) 调整为 varchar(128),并补充一个针对 AutoMigrate 结果的最小测试。

这样做的原因是:当前鉴权流程本身已经会去掉 sk- 前缀再查库,但一些历史部署在迁移到 new-api 时会保留更长的 legacy token key(例如从 sub2api 迁移时,去掉前缀后仍可能是 64 字符)。在现有 char(48) 限制下,这类 key 无法导入;放宽列长度后,不影响现有 48 位 key 的使用,同时为外部迁移脚本保留兼容空间。

⚠️ 对已有部署的影响 / Upgrade impact

  • 运行时兼容性:现有 48 位 token 不受影响,现有鉴权逻辑无需变更;新生成 token 的逻辑也没有变化,仍然是 48 位。
  • 首次升级影响:项目启动时会执行 AutoMigrate,因此已有部署升级到该版本后,首次启动会尝试把 tokens.key 列从 char(48) 放宽到 varchar(128)
  • 运维影响:这属于一次性 schema widening。对 PostgreSQL / MySQL,实际影响取决于数据库版本与表大小,可能带来短暂 DDL 锁或索引调整成本;SQLite 场景下迁移成本通常更高。
  • 回滚边界:如果升级后已经导入了长度大于 48 的 legacy key,则回滚到旧版本不再是无风险操作,因为旧版本模型仍声明为 char(48)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

go test ./controller -run TestTokenAutoMigrateUsesVarchar128KeyColumn -count=1
ok  github.com/QuantumNous/new-api/controller  0.425s

Summary by CodeRabbit

  • Bug Fixes

    • Expanded token key capacity to support longer token values.
  • Tests

    • Added migration tests that seed legacy data, verify schema upgrades preserve data, and validate insertion/readback of longer keys.
    • Improved test DB setup with dialect-aware schema checks and optional compatibility runs against external MySQL/Postgres (with cleanup safeguards).

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Split test DB setup, added dialect-aware migration-compatibility tests that seed a legacy tokens.key (char(48)), run GORM AutoMigrate, assert declared column type changes to varchar(128), verify data preservation and longer-key inserts; changed Token.Key GORM tag to varchar(128).

Changes

Cohort / File(s) Summary
Token Model Schema Update
model/token.go
Changed GORM tag for Token.Key from type:char(48);uniqueIndex to type:varchar(128);uniqueIndex.
Token Schema & Migration Tests
controller/token_test.go
Split test DB setup into openTokenControllerTestDB and migrateTokenControllerTestDB; added legacyToken model, dialect-aware column-inspection helpers for SQLite/MySQL/Postgres, and migration-compatibility tests that seed legacy rows, assert declared column type change after AutoMigrate, verify row preservation, and test longer-key inserts. Supports optional external DB runs via TEST_MYSQL_DSN / TEST_POSTGRES_DSN with conditional cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant DB
    participant Migrator

    Test->>DB: Create legacy `tokens` table (key CHAR(48)) and seed row
    Test->>DB: Inspect declared column type (expect CHAR(48))
    Test->>Migrator: Call AutoMigrate for `Token`
    Migrator->>DB: Apply schema change -> `VARCHAR(128)`
    Test->>DB: Re-inspect declared column type (expect VARCHAR(128))
    Test->>DB: Read seeded row and insert/read back longer key to verify preservation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • Calcium-Ion

Poem

🐇 I hopped from char to varchar with glee,
A legacy seed kept safe with me.
Migrations twirled and kept each key whole,
Longer strings now fit the hole.
I nibble tests and guard the roll.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: relaxing the token key column length for legacy migration compatibility. It accurately captures the primary database schema alteration (char(48) → varchar(128)) and its purpose.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
controller/token_test.go (1)

132-150: Consider covering the actual legacy migration path.

This test proves fresh SQLite tables are created with varchar(128), but the PR’s risk is upgrading an existing char(48) schema. A small migration-path test would better verify the compatibility claim.

Example direction
 func TestTokenAutoMigrateUsesVarchar128KeyColumn(t *testing.T) {
 	db := setupTokenControllerTestDB(t)
 
 	var columns []sqliteColumnInfo
 	if err := db.Raw("PRAGMA table_info(tokens)").Scan(&columns).Error; err != nil {
 		t.Fatalf("failed to inspect token table schema: %v", err)
 	}
 
 	for _, column := range columns {
 		if column.Name == "key" {
 			if strings.ToLower(column.Type) != "varchar(128)" {
 				t.Fatalf("expected key column type varchar(128), got %q", column.Type)
 			}
 			return
 		}
 	}
 
 	t.Fatal("key column not found in token table schema")
 }
+
+func TestTokenAutoMigrateWidensLegacyChar48KeyColumn(t *testing.T) {
+	// Create a DB with the previous schema shape, run AutoMigrate,
+	// then assert the key column is widened to varchar(128).
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/token_test.go` around lines 132 - 150, Add a test that exercises
the legacy migration path by creating a tokens table with the old schema (key
CHAR(48)) directly on the test SQLite DB, then invoking the same auto-migration
code used by setupTokenControllerTestDB (the project’s token migration entry
point—call the same migration function your tests currently invoke) and finally
assert the resulting PRAGMA table_info(tokens) shows the key column is
varchar(128); place this as a new test (e.g.,
TestTokenMigrationFromChar48ToVarchar128) alongside
TestTokenAutoMigrateUsesVarchar128KeyColumn and reuse setupTokenControllerTestDB
to obtain the DB connection and migration invocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@controller/token_test.go`:
- Around line 132-150: Add a test that exercises the legacy migration path by
creating a tokens table with the old schema (key CHAR(48)) directly on the test
SQLite DB, then invoking the same auto-migration code used by
setupTokenControllerTestDB (the project’s token migration entry point—call the
same migration function your tests currently invoke) and finally assert the
resulting PRAGMA table_info(tokens) shows the key column is varchar(128); place
this as a new test (e.g., TestTokenMigrationFromChar48ToVarchar128) alongside
TestTokenAutoMigrateUsesVarchar128KeyColumn and reuse setupTokenControllerTestDB
to obtain the DB connection and migration invocation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 33346ab9-e205-4aeb-9648-1f1299b5d7c8

📥 Commits

Reviewing files that changed from the base of the PR and between 3afa439 and efa3d8b.

📒 Files selected for processing (2)
  • controller/token_test.go
  • model/token.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
controller/token_test.go (1)

194-242: Please verify this migration on MySQL and PostgreSQL too.

These tests only exercise SQLite AutoMigrate/PRAGMA behavior, but the production migration must also widen tokens.key under MySQL and PostgreSQL where GORM uses different DDL and length enforcement differs. Please add integration coverage or documented CI/manual verification for MySQL >= 5.7.8 and PostgreSQL >= 9.6; ideally include a post-migration insert/read of a >48-character key so the legacy-compatibility target is covered. As per coding guidelines, “All database migrations MUST work on all three supported databases (SQLite, MySQL, PostgreSQL).”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/token_test.go` around lines 194 - 242,
TestTokenMigrationFromChar48ToVarchar128 only covers SQLite; extend verification
to MySQL and PostgreSQL by adding equivalent integration checks that run
migrateTokenControllerTestDB and then insert/read a >48-character key to confirm
tokens.key is widened and data preserved. Update or add tests (or CI steps) that
reuse helpers like openTokenControllerTestDB (or add
openTokenControllerTestDBMySQL/openTokenControllerTestDBPostgres) and assert
post-migration column type/behavior (or attempt an insert+select of a
64/128-char key) and that migratedToken fields (Key, Name) remain unchanged; if
real DBs aren’t available in CI, add documented manual verification steps for
MySQL >=5.7.8 and PostgreSQL >=9.6 alongside the SQLite test. Ensure
migrateTokenControllerTestDB is exercised for each DB backend and that any
DB-specific DDL verification replaces getSQLiteColumnType with equivalent
column-type checks for MySQL/Postgres or uses insert/read assertions to prove
the widening.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@controller/token_test.go`:
- Around line 194-242: TestTokenMigrationFromChar48ToVarchar128 only covers
SQLite; extend verification to MySQL and PostgreSQL by adding equivalent
integration checks that run migrateTokenControllerTestDB and then insert/read a
>48-character key to confirm tokens.key is widened and data preserved. Update or
add tests (or CI steps) that reuse helpers like openTokenControllerTestDB (or
add openTokenControllerTestDBMySQL/openTokenControllerTestDBPostgres) and assert
post-migration column type/behavior (or attempt an insert+select of a
64/128-char key) and that migratedToken fields (Key, Name) remain unchanged; if
real DBs aren’t available in CI, add documented manual verification steps for
MySQL >=5.7.8 and PostgreSQL >=9.6 alongside the SQLite test. Ensure
migrateTokenControllerTestDB is exercised for each DB backend and that any
DB-specific DDL verification replaces getSQLiteColumnType with equivalent
column-type checks for MySQL/Postgres or uses insert/read assertions to prove
the widening.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6f097a6-c0a9-40de-884b-a47051a163b7

📥 Commits

Reviewing files that changed from the base of the PR and between efa3d8b and d586284.

📒 Files selected for processing (1)
  • controller/token_test.go

@XiaoAI1024

Copy link
Copy Markdown
Contributor Author

补充说明:已按 CodeRabbit 的建议补上跨数据库迁移测试。

新增测试:

  • TestTokenMigrationFromChar48ToVarchar128MySQL
  • TestTokenMigrationFromChar48ToVarchar128Postgres

这两个测试通过环境变量注入 DSN:

  • TEST_MYSQL_DSN
  • TEST_POSTGRES_DSN

本地我已用 Docker 起临时 MySQL 8.4 / PostgreSQL 16 实际跑过:

TEST_MYSQL_DSN='root:codex@tcp(127.0.0.1:13306)/newapi_test?charset=utf8mb4&parseTime=True&loc=Local' \
TEST_POSTGRES_DSN='host=127.0.0.1 port=15432 user=postgres password=codex dbname=newapi_test sslmode=disable' \
go test ./controller -run 'TestToken(MigrationFromChar48ToVarchar128(MySQL|Postgres)?|AutoMigrateUsesVarchar128KeyColumn)$' -count=1

TEST_MYSQL_DSN='root:codex@tcp(127.0.0.1:13306)/newapi_test?charset=utf8mb4&parseTime=True&loc=Local' \
TEST_POSTGRES_DSN='host=127.0.0.1 port=15432 user=postgres password=codex dbname=newapi_test sslmode=disable' \
go test ./controller -count=1

结果:

ok   github.com/QuantumNous/new-api/controller  0.596s
ok   github.com/QuantumNous/new-api/controller  0.623s

测试覆盖点:

  • 先用旧 schema 建 tokens.key = char(48)
  • 再执行当前 AutoMigrate
  • 断言列被放宽到 varchar(128)
  • 验证旧数据保留
  • 验证迁移后可插入并读回 >48 字符的新 key

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@controller/token_test.go`:
- Around line 145-147: The test currently unconditionally executes db.Exec("DROP
TABLE IF EXISTS tokens") in t.Cleanup (and similarly at lines ~269-280), which
can wipe a real external DB; update the test harness to guard external DB runs
by detecting TEST_MYSQL_DSN or TEST_POSTGRES_DSN and refusing to drop or modify
an existing "tokens" table: if an external DSN is present, first check for the
existence of the "tokens" table via the DB connection and fail the test (or
skip) if it already exists, and for this test only create/cleanup a uniquely
named table (or use a test-specific prefix) instead of the global "tokens" name;
apply the same guard logic to the setup and t.Cleanup blocks referencing
db.Exec("DROP TABLE IF EXISTS tokens") so only tables created by this test are
removed and external DBs are protected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d2932f24-f750-41f6-877e-e3905ddc7278

📥 Commits

Reviewing files that changed from the base of the PR and between d586284 and c9ff37c.

📒 Files selected for processing (1)
  • controller/token_test.go

Comment thread controller/token_test.go
@XiaoAI1024

Copy link
Copy Markdown
Contributor Author

@Calcium-Ion 打扰了,这个 PR 这边已经按 CodeRabbit 的建议补齐了迁移路径测试、MySQL/PostgreSQL 覆盖以及外部库保护逻辑;最新一轮 CodeRabbit 也已经没有 actionable comments。\n\n如果你方便的话,麻烦帮看一下这个 PR 是否可以继续推进,感谢。

@XiaoAI1024
XiaoAI1024 force-pushed the codex/legacy-token-key-compat branch 2 times, most recently from 007c418 to fc98d36 Compare April 23, 2026 05:28
@XiaoAI1024
XiaoAI1024 force-pushed the codex/legacy-token-key-compat branch from fc98d36 to 4947452 Compare April 23, 2026 05:29
@XiaoAI1024
XiaoAI1024 requested a review from seefs001 April 23, 2026 05:29
@XiaoAI1024

Copy link
Copy Markdown
Contributor Author

提交没签名导致不能合并,签名后重新提交了

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
controller/token_test.go (1)

252-270: Postgres branch: fragile formatting when character_maximum_length is NULL.

For character varying / character with no explicit length (e.g., unbounded varchar), maxLength.Valid will be false and maxLength.Int64 is 0, so Lines 261-264 would emit misleading strings like varchar(0) or char(0). The current migration tests only exercise bounded lengths (char(48)varchar(128)), so this isn't a bug today — just brittle if the helper is reused for other columns later.

♻️ Optional hardening
 		switch strings.ToLower(dataType) {
 		case "character varying":
+			if !maxLength.Valid {
+				return "varchar"
+			}
 			return fmt.Sprintf("varchar(%d)", maxLength.Int64)
 		case "character":
+			if !maxLength.Valid {
+				return "char"
+			}
 			return fmt.Sprintf("char(%d)", maxLength.Int64)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@controller/token_test.go` around lines 252 - 270, The helper that inspects
the Postgres column currently reads dataType and maxLength and formats
"varchar(%d)" or "char(%d)" even when maxLength.Valid is false; update the
switch in the token_test.go inspection logic (the block that scans into dataType
and maxLength and the switch on strings.ToLower(dataType)) to check
maxLength.Valid before using maxLength.Int64 and, for unbounded types (character
varying / character) when maxLength.Valid is false, return the unparameterized
type name ("varchar" or "char") instead of "varchar(0)" or "char(0)"; also keep
the existing fallback that uses maxLength only when maxLength.Valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@controller/token_test.go`:
- Around line 252-270: The helper that inspects the Postgres column currently
reads dataType and maxLength and formats "varchar(%d)" or "char(%d)" even when
maxLength.Valid is false; update the switch in the token_test.go inspection
logic (the block that scans into dataType and maxLength and the switch on
strings.ToLower(dataType)) to check maxLength.Valid before using maxLength.Int64
and, for unbounded types (character varying / character) when maxLength.Valid is
false, return the unparameterized type name ("varchar" or "char") instead of
"varchar(0)" or "char(0)"; also keep the existing fallback that uses maxLength
only when maxLength.Valid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 67f4803e-ab23-4981-973c-929c3a9554ec

📥 Commits

Reviewing files that changed from the base of the PR and between eb319ce and 007c418.

📒 Files selected for processing (2)
  • controller/token_test.go
  • model/token.go
✅ Files skipped from review due to trivial changes (1)
  • model/token.go

@Calcium-Ion
Calcium-Ion merged commit 11f8d42 into QuantumNous:main Apr 23, 2026
1 check passed
Jinxuans referenced this pull request in TokFlux-Org/TokFlux May 9, 2026
Relax token key column length for legacy migration compatibility
@coderabbitai coderabbitai Bot mentioned this pull request Jun 22, 2026
11 tasks
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.

3 participants