相关组件
后端服务及API
Bug 描述
When a tenant setting is updated via the PUT /tenants/kv/{key} endpoints (e.g., web-search-config, parser-engine-config, storage-engine-config, retrieval-config), the encrypted api_key is silently reverted to plaintext in the database.
Root cause: tenantRepository.UpdateTenant() uses db.Updates(tenant) which does not trigger GORM's BeforeSave hook. The AfterFind hook decrypts enc:v1:... → sk-... (plaintext) when loading the tenant, and then Updates() writes the decrypted plaintext back to the database.
The existing codebase already acknowledges this GORM limitation — both CreateTenant and UpdateAPIKey (renamed from RegenerateApiKey) contain manual EncryptAESGCM calls with the comment:
// Manually encrypt APIKey before update, because db.Updates() does not trigger BeforeSave hook
However, the general UpdateTenant path is missing this treatment.
Reproduction flow (UpdateTenantKV path):
AfterFind hook decrypts api_key: enc:v1:... → sk-... in the Go struct
- User updates a config via API (e.g.,
PUT /tenants/kv/retrieval-config)
- Handler loads full tenant from context (already decrypted), modifies one config field
service.UpdateTenant() → repo.UpdateTenant() → db.Updates(tenant)
BeforeSave is not triggered by Updates()
- Decrypted plaintext
sk-... overwrites the encrypted value in the database
Note: ModelParameters JSONB encryption is not affected — its Value() method (implementing driver.Valuer) is correctly called by GORM during Updates().
期望行为
- Tenant
api_key remains enc:v1:... in the database after any tenant settings update
- The
UpdateTenant repository method should re-encrypt api_key before calling db.Updates(), consistent with the existing pattern in CreateTenant and UpdateAPIKey
相关日志
N/A — this is a silent data corruption issue discovered through code analysis. No error is logged when the encryption is lost.
操作系统
N/A (server-side logic bug, platform-independent)
相关组件
后端服务及API
Bug 描述
When a tenant setting is updated via the
PUT /tenants/kv/{key}endpoints (e.g.,web-search-config,parser-engine-config,storage-engine-config,retrieval-config), the encryptedapi_keyis silently reverted to plaintext in the database.Root cause:
tenantRepository.UpdateTenant()usesdb.Updates(tenant)which does not trigger GORM'sBeforeSavehook. TheAfterFindhook decryptsenc:v1:...→sk-...(plaintext) when loading the tenant, and thenUpdates()writes the decrypted plaintext back to the database.The existing codebase already acknowledges this GORM limitation — both
CreateTenantandUpdateAPIKey(renamed fromRegenerateApiKey) contain manualEncryptAESGCMcalls with the comment:// Manually encrypt APIKey before update, because db.Updates() does not trigger BeforeSave hookHowever, the general
UpdateTenantpath is missing this treatment.Reproduction flow (UpdateTenantKV path):
AfterFindhook decryptsapi_key:enc:v1:...→sk-...in the Go structPUT /tenants/kv/retrieval-config)service.UpdateTenant()→repo.UpdateTenant()→db.Updates(tenant)BeforeSaveis not triggered byUpdates()sk-...overwrites the encrypted value in the databaseNote:
ModelParametersJSONB encryption is not affected — itsValue()method (implementingdriver.Valuer) is correctly called by GORM duringUpdates().期望行为
api_keyremainsenc:v1:...in the database after any tenant settings updateUpdateTenantrepository method should re-encryptapi_keybefore callingdb.Updates(), consistent with the existing pattern inCreateTenantandUpdateAPIKey相关日志
N/A — this is a silent data corruption issue discovered through code analysis. No error is logged when the encryption is lost.
操作系统
N/A (server-side logic bug, platform-independent)