diff --git a/app/models/application.rb b/app/models/application.rb index 25d85e0..a866659 100644 --- a/app/models/application.rb +++ b/app/models/application.rb @@ -36,6 +36,7 @@ class Application < ApplicationRecord has_many :allowed_groups, through: :application_groups, source: :group has_many :application_user_claims, dependent: :destroy has_many :oidc_authorization_codes, dependent: :destroy + has_many :oidc_device_codes, dependent: :destroy has_many :oidc_access_tokens, dependent: :destroy has_many :oidc_refresh_tokens, dependent: :destroy has_many :oidc_user_consents, dependent: :destroy diff --git a/db/migrate/20260719000006_add_cascade_to_oidc_device_codes_application_fk.rb b/db/migrate/20260719000006_add_cascade_to_oidc_device_codes_application_fk.rb new file mode 100644 index 0000000..f323150 --- /dev/null +++ b/db/migrate/20260719000006_add_cascade_to_oidc_device_codes_application_fk.rb @@ -0,0 +1,14 @@ +class AddCascadeToOidcDeviceCodesApplicationFk < ActiveRecord::Migration[8.1] + # Deleting an application left its oidc_device_codes orphaned, tripping this + # FK and 500ing the destroy. Mirror application_user_claims: cascade at the DB + # level so the delete is safe even if the model-layer cascade is bypassed. + def up + remove_foreign_key :oidc_device_codes, :applications + add_foreign_key :oidc_device_codes, :applications, on_delete: :cascade + end + + def down + remove_foreign_key :oidc_device_codes, :applications + add_foreign_key :oidc_device_codes, :applications + end +end diff --git a/db/schema.rb b/db/schema.rb index 245a0dc..fa061bf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_07_19_000005) do +ActiveRecord::Schema[8.1].define(version: 2026_07_19_000006) do create_table "active_storage_attachments", force: :cascade do |t| t.bigint "blob_id", null: false t.datetime "created_at", null: false @@ -329,7 +329,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_07_19_000005) do add_foreign_key "oidc_access_tokens", "users" add_foreign_key "oidc_authorization_codes", "applications" add_foreign_key "oidc_authorization_codes", "users" - add_foreign_key "oidc_device_codes", "applications" + add_foreign_key "oidc_device_codes", "applications", on_delete: :cascade add_foreign_key "oidc_device_codes", "users" add_foreign_key "oidc_refresh_tokens", "applications" add_foreign_key "oidc_refresh_tokens", "oidc_access_tokens" diff --git a/test/models/application_test.rb b/test/models/application_test.rb index 4cda8f7..71d1fc3 100644 --- a/test/models/application_test.rb +++ b/test/models/application_test.rb @@ -81,4 +81,14 @@ class ApplicationTest < ActiveSupport::TestCase assert app.valid?, app.errors.full_messages.to_sentence end + + test "destroying an application with a pending device code succeeds (regression for FK 500)" do + app = applications(:kavita_app) + device_code = app.oidc_device_codes.create! + + assert_difference("OidcDeviceCode.count", -1) do + assert_nothing_raised { app.destroy } + end + refute OidcDeviceCode.exists?(device_code.id) + end end