Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ Write each change in both `### English` and `### 中文` under `## Unreleased`.
- Replace native Logs and Models filter dropdowns with compact HeroUI Select controls that match the 32px toolbar
- Add named client API keys with optional provider allowlists, and show the console administrator key on System
- Store an empty client-key provider allowlist as `[]` instead of JSON `null`
- Keep the v0.2.20 bytes for provider-model settings migration 007, and accept the later tab-indented checksum so existing databases can boot

### 中文

- Logs 和模型页的筛选下拉改用紧凑 HeroUI Select,高度对齐 32px 工具栏
- 新增可限制供应商的客户端 API 密钥,并在系统页显示控制台管理员密钥
- 客户端密钥未限制供应商时写入 `[]`,不再存成 JSON `null`
- 007 供应商模型设置迁移保持 v0.2.20 原文,并接受后来误改缩进后的 checksum,已有数据库可以启动

## 0.2.20 - 2026-08-29

Expand Down
52 changes: 52 additions & 0 deletions internal/accounts/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,55 @@ func TestStoreOpensDatabaseWithV0219RequestLogProviderChecksum(t *testing.T) {
}
reopened.Close()
}

const (
providerModelSettingsMigration = "007_provider_model_settings.sql"
providerModelSettingsChecksum = "b48b62c578bff658ee5843776fe16dd35d11d86c84800398c98d666eb777968a"
providerModelSettingsRetabbed = "8940e0c639008f811dd844add98865f700f32ca0a4fd672c1bcc0adf3f69ef71"
)

func TestProviderModelSettingsMigrationKeepsV0220Bytes(t *testing.T) {
var migration sqliteMigration
for _, item := range sqliteMigrations {
if item.filename == providerModelSettingsMigration {
migration = item
break
}
}
if migration.filename == "" {
t.Fatal("missing 007_provider_model_settings.sql")
}
got := migrationChecksum(migration.sql)
if got != providerModelSettingsChecksum {
t.Fatalf("007 checksum = %s, want v0.2.20 %s", got, providerModelSettingsChecksum)
}
if !checksumAccepted(migration, providerModelSettingsRetabbed) {
t.Fatal("expected retabbed 007 checksum to remain accepted")
}
}

func TestStoreOpensDatabaseWithRetabbedProviderModelSettingsChecksum(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "qoder.db")
store, err := OpenStore(dbPath)
if err != nil {
t.Fatal(err)
}
var recorded string
if err := store.db.QueryRow("SELECT checksum FROM schema_migrations WHERE filename = ?", providerModelSettingsMigration).Scan(&recorded); err != nil {
t.Fatal(err)
}
if recorded != providerModelSettingsChecksum {
t.Fatalf("fresh 007 checksum = %s, want %s", recorded, providerModelSettingsChecksum)
}
if _, err := store.db.Exec("UPDATE schema_migrations SET checksum = ? WHERE filename = ?", providerModelSettingsRetabbed, providerModelSettingsMigration); err != nil {
t.Fatal(err)
}
if err := store.Close(); err != nil {
t.Fatal(err)
}
reopened, err := OpenStore(dbPath)
if err != nil {
t.Fatal(err)
}
reopened.Close()
}
16 changes: 9 additions & 7 deletions internal/accounts/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,15 @@ CREATE INDEX IF NOT EXISTS request_logs_provider ON request_logs(provider);`,
// v0.2.19 retabbed this SQL; keep that checksum bootable.
legacyChecksums: []string{"9b96b8d63286519b20791d2a3688c0b71efba6204015250ae9864c5cbcd1f0b4"}},
{filename: "007_provider_model_settings.sql", sql: `
CREATE TABLE IF NOT EXISTS provider_model_settings (
provider TEXT NOT NULL,
model_id TEXT NOT NULL,
max_mode INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
PRIMARY KEY (provider, model_id)
);`},
CREATE TABLE IF NOT EXISTS provider_model_settings (
provider TEXT NOT NULL,
model_id TEXT NOT NULL,
max_mode INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
PRIMARY KEY (provider, model_id)
);`,
// Named-key work retabbed this SQL on main before a release.
legacyChecksums: []string{"8940e0c639008f811dd844add98865f700f32ca0a4fd672c1bcc0adf3f69ef71"}},
{filename: "008_api_keys.sql", sql: `
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
Expand Down
Loading