diff --git a/backend/plugins/asana/models/migrationscripts/20260509000001_encrypt_connection_token.go b/backend/plugins/asana/models/migrationscripts/20260509000001_encrypt_connection_token.go index 6a67eaceead..fee89ca11c5 100644 --- a/backend/plugins/asana/models/migrationscripts/20260509000001_encrypt_connection_token.go +++ b/backend/plugins/asana/models/migrationscripts/20260509000001_encrypt_connection_token.go @@ -18,6 +18,8 @@ limitations under the License. package migrationscripts import ( + "fmt" + "github.com/apache/incubator-devlake/core/context" "github.com/apache/incubator-devlake/core/dal" "github.com/apache/incubator-devlake/core/errors" @@ -39,7 +41,13 @@ func (*encryptConnectionToken) Up(basicRes context.BasicRes) errors.Error { db := basicRes.GetDal() encKey := basicRes.GetConfig(plugin.EncodeKeyEnvStr) if encKey == "" { - return errors.BadInput.New("asana invalid encKey") + return errors.BadInput.New( + "ENCRYPTION_SECRET is not set — this is required to encrypt existing Asana connection " + + "tokens as part of this migration. Please set the ENCRYPTION_SECRET environment " + + "variable to the value of ENCODE_KEY from your previous deployment's .env file, " + + "then retry the migration. See https://devlake.apache.org/docs/GettingStarted/Upgrade/ " + + "for details.", + ) } cursor, err := db.Cursor(dal.From(&asanaConnectionTokenPlain{})) @@ -56,9 +64,22 @@ func (*encryptConnectionToken) Up(basicRes context.BasicRes) errors.Error { if row.Token == "" { continue } + + // Skip tokens already encrypted, so retries don't double-encrypt them. + if _, decryptErr := plugin.Decrypt(encKey, row.Token); decryptErr == nil { + continue + } + encryptedToken, err := plugin.Encrypt(encKey, row.Token) if err != nil { - return err + return errors.Default.Wrap(err, + fmt.Sprintf( + "failed to encrypt token for asana connection id=%d — this usually means "+ + "ENCRYPTION_SECRET does not match the ENCODE_KEY used to originally store "+ + "this connection's token", + row.ID, + ), + ) } err = db.UpdateColumns( row.TableName(), diff --git a/backend/server/api/api.go b/backend/server/api/api.go index b0dfd74dd94..4c880ec9c50 100644 --- a/backend/server/api/api.go +++ b/backend/server/api/api.go @@ -130,9 +130,11 @@ func SetupApiServer(router *gin.Engine) { // Endpoint to proceed database migration — listed in auth.publicPaths because // auth tables may not exist yet when migration is pending. router.GET("/proceed-db-migration", func(ctx *gin.Context) { - // Execute database migration - errors.Must(services.ExecuteMigration()) - // Return success response + // Surface the real migration error to the client instead of a bare 500. + if err := services.ExecuteMigration(); err != nil { + shared.ApiOutputError(ctx, err) + return + } shared.ApiOutputSuccess(ctx, nil, http.StatusOK) })