Browse Source

feat(backup): Expose HybridCloudForeignKeys as relations (#54797)

PR #54324 added a `dependencies()` method to deduce the dependency
relations between models, and PR #54610 utilized this information to do
foreign key remapping when importing from a backup JSON file. However,
the dependency calculation as defined in those files did not account for
`HybridCloudForeignKey` relations.

Issue: getsentry/team-ospo#166
Alex Zaslavsky 1 year ago
parent
commit
98bda36460

+ 234 - 5
fixtures/backup/model_dependencies/detailed.json

@@ -22,6 +22,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.Activity",
@@ -30,7 +34,12 @@
     ]
   },
   "sentry.Actor": {
-    "foreign_keys": {},
+    "foreign_keys": {
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      }
+    },
     "model": "sentry.Actor",
     "silos": [
       "REGION"
@@ -65,6 +74,10 @@
       "previous_alert_rule": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.AlertRule"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.AlertRuleActivity",
@@ -105,6 +118,14 @@
       "alert_rule_trigger": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.AlertRuleTrigger"
+      },
+      "integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Integration"
+      },
+      "sentry_app_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.SentryApp"
       }
     },
     "model": "sentry.AlertRuleTriggerAction",
@@ -173,7 +194,12 @@
     ]
   },
   "sentry.ApiKey": {
-    "foreign_keys": {},
+    "foreign_keys": {
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      }
+    },
     "model": "sentry.ApiKey",
     "silos": [
       "CONTROL"
@@ -265,6 +291,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.ApiKey"
       },
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
       "target_user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
@@ -292,7 +322,12 @@
     ]
   },
   "sentry.AuthProvider": {
-    "foreign_keys": {},
+    "foreign_keys": {
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      }
+    },
     "model": "sentry.AuthProvider",
     "silos": [
       "CONTROL"
@@ -448,6 +483,10 @@
   },
   "sentry.Dashboard": {
     "foreign_keys": {
+      "created_by_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -557,6 +596,10 @@
   },
   "sentry.DiscoverSavedQuery": {
     "foreign_keys": {
+      "created_by_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -679,6 +722,10 @@
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.ExportedData",
@@ -704,6 +751,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.Actor"
       },
+      "integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Integration"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -711,6 +762,10 @@
       "team": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Team"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.ExternalActor",
@@ -720,6 +775,10 @@
   },
   "sentry.ExternalIssue": {
     "foreign_keys": {
+      "integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Integration"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -834,6 +893,10 @@
       "team": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Team"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupAssignee",
@@ -850,6 +913,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupBookmark",
@@ -1009,6 +1076,10 @@
       "team": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Team"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupOwner",
@@ -1075,6 +1146,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupSeen",
@@ -1091,6 +1166,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupShare",
@@ -1119,6 +1198,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.GroupSubscription",
@@ -1182,6 +1265,10 @@
       "incident": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Incident"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.IncidentActivity",
@@ -1210,6 +1297,10 @@
       "incident": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Incident"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.IncidentSeen",
@@ -1238,6 +1329,10 @@
       "incident": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Incident"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.IncidentSubscription",
@@ -1372,9 +1467,17 @@
   },
   "sentry.NotificationAction": {
     "foreign_keys": {
+      "integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Integration"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "sentry_app_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.SentryApp"
       }
     },
     "model": "sentry.NotificationAction",
@@ -1400,6 +1503,14 @@
   },
   "sentry.NotificationSetting": {
     "foreign_keys": {
+      "target_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Actor"
+      },
+      "team_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Team"
+      },
       "user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
@@ -1412,6 +1523,10 @@
   },
   "sentry.NotificationSettingOption": {
     "foreign_keys": {
+      "team_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Team"
+      },
       "user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
@@ -1424,6 +1539,10 @@
   },
   "sentry.NotificationSettingProvider": {
     "foreign_keys": {
+      "team_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Team"
+      },
       "user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
@@ -1446,6 +1565,14 @@
       "created_by": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
+      },
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
+      "project_last_used_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Project"
       }
     },
     "model": "sentry.OrgAuthToken",
@@ -1466,6 +1593,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.OrganizationMember"
       },
+      "requester_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "team": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Team"
@@ -1493,6 +1624,10 @@
       "integration": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Integration"
+      },
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
       }
     },
     "model": "sentry.OrganizationIntegration",
@@ -1509,9 +1644,17 @@
   },
   "sentry.OrganizationMember": {
     "foreign_keys": {
+      "inviter_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.OrganizationMember",
@@ -1525,6 +1668,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
       },
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
       "user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
@@ -1560,6 +1707,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.OrganizationOnboardingTask",
@@ -1679,6 +1830,10 @@
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.ProjectBookmark",
@@ -1716,6 +1871,10 @@
   },
   "sentry.ProjectIntegration": {
     "foreign_keys": {
+      "integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Integration"
+      },
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
@@ -1803,6 +1962,10 @@
   },
   "sentry.ProjectTransactionThreshold": {
     "foreign_keys": {
+      "edited_by_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -1819,6 +1982,10 @@
   },
   "sentry.ProjectTransactionThresholdOverride": {
     "foreign_keys": {
+      "edited_by_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
@@ -1834,7 +2001,12 @@
     ]
   },
   "sentry.PromptsActivity": {
-    "foreign_keys": {},
+    "foreign_keys": {
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      }
+    },
     "model": "sentry.PromptsActivity",
     "silos": [
       "REGION"
@@ -1913,6 +2085,10 @@
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.RecentSearch",
@@ -1960,6 +2136,10 @@
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "owner_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.Release",
@@ -2100,6 +2280,10 @@
   },
   "sentry.RepositoryProjectPathConfig": {
     "foreign_keys": {
+      "organization_integration_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.OrganizationIntegration"
+      },
       "project": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Project"
@@ -2147,6 +2331,10 @@
       "rule": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Rule"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.RuleActivity",
@@ -2180,9 +2368,17 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.AlertRule"
       },
+      "owner_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
+      },
       "rule": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Rule"
+      },
+      "user_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.RuleSnooze",
@@ -2195,6 +2391,10 @@
       "organization": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.Organization"
+      },
+      "owner_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.User"
       }
     },
     "model": "sentry.SavedSearch",
@@ -2219,6 +2419,10 @@
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"
       },
+      "owner_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
       "proxy_user": {
         "kind": "DefaultOneToOneField",
         "model": "sentry.User"
@@ -2263,6 +2467,10 @@
         "kind": "DefaultOneToOneField",
         "model": "sentry.ApiToken"
       },
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
       "sentry_app": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.SentryApp"
@@ -2275,6 +2483,10 @@
   },
   "sentry.SentryAppInstallationForProvider": {
     "foreign_keys": {
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
       "sentry_app_installation": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.SentryAppInstallation"
@@ -2314,7 +2526,16 @@
     ]
   },
   "sentry.ServiceHook": {
-    "foreign_keys": {},
+    "foreign_keys": {
+      "application_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.ApiApplication"
+      },
+      "installation_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.SentryAppInstallation"
+      }
+    },
     "model": "sentry.ServiceHook",
     "silos": [
       "REGION"
@@ -2459,6 +2680,14 @@
   },
   "sentry.UserOption": {
     "foreign_keys": {
+      "organization_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Organization"
+      },
+      "project_id": {
+        "kind": "HybridCloudForeignKey",
+        "model": "sentry.Project"
+      },
       "user": {
         "kind": "FlexibleForeignKey",
         "model": "sentry.User"

+ 93 - 34
fixtures/backup/model_dependencies/flat.json

@@ -3,16 +3,20 @@
   "replays.ReplayRecordingSegment": [],
   "sentry.Activity": [
     "sentry.Group",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
+  ],
+  "sentry.Actor": [
+    "sentry.User"
   ],
-  "sentry.Actor": [],
   "sentry.AlertRule": [
     "sentry.Actor",
     "sentry.Organization",
     "sentry.SnubaQuery"
   ],
   "sentry.AlertRuleActivity": [
-    "sentry.AlertRule"
+    "sentry.AlertRule",
+    "sentry.User"
   ],
   "sentry.AlertRuleExcludedProjects": [
     "sentry.AlertRule",
@@ -22,7 +26,9 @@
     "sentry.AlertRule"
   ],
   "sentry.AlertRuleTriggerAction": [
-    "sentry.AlertRuleTrigger"
+    "sentry.AlertRuleTrigger",
+    "sentry.Integration",
+    "sentry.SentryApp"
   ],
   "sentry.AlertRuleTriggerExclusion": [
     "sentry.AlertRuleTrigger",
@@ -39,7 +45,9 @@
     "sentry.ApiApplication",
     "sentry.User"
   ],
-  "sentry.ApiKey": [],
+  "sentry.ApiKey": [
+    "sentry.Organization"
+  ],
   "sentry.ApiToken": [
     "sentry.ApiApplication",
     "sentry.User"
@@ -61,13 +69,16 @@
   ],
   "sentry.AuditLogEntry": [
     "sentry.ApiKey",
+    "sentry.Organization",
     "sentry.User"
   ],
   "sentry.AuthIdentity": [
     "sentry.AuthProvider",
     "sentry.User"
   ],
-  "sentry.AuthProvider": [],
+  "sentry.AuthProvider": [
+    "sentry.Organization"
+  ],
   "sentry.AuthProviderDefaultTeams": [],
   "sentry.Authenticator": [
     "sentry.User"
@@ -100,7 +111,8 @@
     "sentry.Project"
   ],
   "sentry.Dashboard": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.DashboardProject": [
     "sentry.Dashboard",
@@ -125,7 +137,8 @@
     "sentry.Release"
   ],
   "sentry.DiscoverSavedQuery": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.DiscoverSavedQueryProject": [
     "sentry.DiscoverSavedQuery",
@@ -151,17 +164,21 @@
   ],
   "sentry.EventUser": [],
   "sentry.ExportedData": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.ExportedDataBlob": [
     "sentry.ExportedData"
   ],
   "sentry.ExternalActor": [
     "sentry.Actor",
+    "sentry.Integration",
     "sentry.Organization",
-    "sentry.Team"
+    "sentry.Team",
+    "sentry.User"
   ],
   "sentry.ExternalIssue": [
+    "sentry.Integration",
     "sentry.Organization"
   ],
   "sentry.FeatureAdoption": [
@@ -189,11 +206,13 @@
   "sentry.GroupAssignee": [
     "sentry.Group",
     "sentry.Project",
-    "sentry.Team"
+    "sentry.Team",
+    "sentry.User"
   ],
   "sentry.GroupBookmark": [
     "sentry.Group",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.GroupCommitResolution": [],
   "sentry.GroupEmailThread": [
@@ -232,7 +251,8 @@
     "sentry.Group",
     "sentry.Organization",
     "sentry.Project",
-    "sentry.Team"
+    "sentry.Team",
+    "sentry.User"
   ],
   "sentry.GroupRedirect": [],
   "sentry.GroupRelease": [],
@@ -247,18 +267,21 @@
   ],
   "sentry.GroupSeen": [
     "sentry.Group",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.GroupShare": [
     "sentry.Group",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.GroupSnooze": [
     "sentry.Group"
   ],
   "sentry.GroupSubscription": [
     "sentry.Group",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.GroupTombstone": [
     "sentry.Project"
@@ -273,21 +296,24 @@
     "sentry.Organization"
   ],
   "sentry.IncidentActivity": [
-    "sentry.Incident"
+    "sentry.Incident",
+    "sentry.User"
   ],
   "sentry.IncidentProject": [
     "sentry.Incident",
     "sentry.Project"
   ],
   "sentry.IncidentSeen": [
-    "sentry.Incident"
+    "sentry.Incident",
+    "sentry.User"
   ],
   "sentry.IncidentSnapshot": [
     "sentry.Incident",
     "sentry.TimeSeriesSnapshot"
   ],
   "sentry.IncidentSubscription": [
-    "sentry.Incident"
+    "sentry.Incident",
+    "sentry.User"
   ],
   "sentry.IncidentTrigger": [
     "sentry.AlertRuleTrigger",
@@ -316,41 +342,53 @@
   ],
   "sentry.MonitorLocation": [],
   "sentry.NotificationAction": [
-    "sentry.Organization"
+    "sentry.Integration",
+    "sentry.Organization",
+    "sentry.SentryApp"
   ],
   "sentry.NotificationActionProject": [
     "sentry.NotificationAction",
     "sentry.Project"
   ],
   "sentry.NotificationSetting": [
+    "sentry.Actor",
+    "sentry.Team",
     "sentry.User"
   ],
   "sentry.NotificationSettingOption": [
+    "sentry.Team",
     "sentry.User"
   ],
   "sentry.NotificationSettingProvider": [
+    "sentry.Team",
     "sentry.User"
   ],
   "sentry.Option": [],
   "sentry.OrgAuthToken": [
+    "sentry.Organization",
+    "sentry.Project",
     "sentry.User"
   ],
   "sentry.Organization": [],
   "sentry.OrganizationAccessRequest": [
     "sentry.OrganizationMember",
-    "sentry.Team"
+    "sentry.Team",
+    "sentry.User"
   ],
   "sentry.OrganizationAvatar": [
     "sentry.Organization"
   ],
   "sentry.OrganizationIntegration": [
-    "sentry.Integration"
+    "sentry.Integration",
+    "sentry.Organization"
   ],
   "sentry.OrganizationMapping": [],
   "sentry.OrganizationMember": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.OrganizationMemberMapping": [
+    "sentry.Organization",
     "sentry.User"
   ],
   "sentry.OrganizationMemberTeam": [
@@ -359,7 +397,8 @@
   ],
   "sentry.OrganizationOnboardingTask": [
     "sentry.Organization",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.OrganizationOption": [
     "sentry.Organization"
@@ -388,7 +427,8 @@
     "sentry.Project"
   ],
   "sentry.ProjectBookmark": [
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.ProjectCodeOwners": [
     "sentry.Project",
@@ -398,6 +438,7 @@
     "sentry.File"
   ],
   "sentry.ProjectIntegration": [
+    "sentry.Integration",
     "sentry.Project"
   ],
   "sentry.ProjectKey": [
@@ -420,13 +461,17 @@
   ],
   "sentry.ProjectTransactionThreshold": [
     "sentry.Organization",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
   ],
   "sentry.ProjectTransactionThresholdOverride": [
     "sentry.Organization",
-    "sentry.Project"
+    "sentry.Project",
+    "sentry.User"
+  ],
+  "sentry.PromptsActivity": [
+    "sentry.User"
   ],
-  "sentry.PromptsActivity": [],
   "sentry.PullRequest": [
     "sentry.CommitAuthor"
   ],
@@ -445,7 +490,8 @@
     "sentry.Project"
   ],
   "sentry.RecentSearch": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.RegionOutbox": [],
   "sentry.RegionScheduledDeletion": [],
@@ -453,7 +499,8 @@
   "sentry.Relay": [],
   "sentry.RelayUsage": [],
   "sentry.Release": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.ReleaseActivity": [
     "sentry.Release"
@@ -488,6 +535,7 @@
   ],
   "sentry.Repository": [],
   "sentry.RepositoryProjectPathConfig": [
+    "sentry.OrganizationIntegration",
     "sentry.Project",
     "sentry.Repository"
   ],
@@ -499,7 +547,8 @@
     "sentry.Project"
   ],
   "sentry.RuleActivity": [
-    "sentry.Rule"
+    "sentry.Rule",
+    "sentry.User"
   ],
   "sentry.RuleFireHistory": [
     "sentry.Group",
@@ -508,14 +557,17 @@
   ],
   "sentry.RuleSnooze": [
     "sentry.AlertRule",
-    "sentry.Rule"
+    "sentry.Rule",
+    "sentry.User"
   ],
   "sentry.SavedSearch": [
-    "sentry.Organization"
+    "sentry.Organization",
+    "sentry.User"
   ],
   "sentry.ScheduledDeletion": [],
   "sentry.SentryApp": [
     "sentry.ApiApplication",
+    "sentry.Organization",
     "sentry.User"
   ],
   "sentry.SentryAppAvatar": [
@@ -527,9 +579,11 @@
   "sentry.SentryAppInstallation": [
     "sentry.ApiGrant",
     "sentry.ApiToken",
+    "sentry.Organization",
     "sentry.SentryApp"
   ],
   "sentry.SentryAppInstallationForProvider": [
+    "sentry.Organization",
     "sentry.SentryAppInstallation"
   ],
   "sentry.SentryAppInstallationToken": [
@@ -539,7 +593,10 @@
   "sentry.SentryFunction": [
     "sentry.Organization"
   ],
-  "sentry.ServiceHook": [],
+  "sentry.ServiceHook": [
+    "sentry.ApiApplication",
+    "sentry.SentryAppInstallation"
+  ],
   "sentry.ServiceHookProject": [
     "sentry.ServiceHook"
   ],
@@ -573,6 +630,8 @@
     "sentry.User"
   ],
   "sentry.UserOption": [
+    "sentry.Organization",
+    "sentry.Project",
     "sentry.User"
   ],
   "sentry.UserPermission": [

+ 41 - 41
fixtures/backup/model_dependencies/sorted.json

@@ -3,12 +3,9 @@
   "sites.Site",
   "sentry.Option",
   "sentry.ControlOption",
-  "sentry.Actor",
   "sentry.RegionOutbox",
   "sentry.ControlOutbox",
-  "sentry.ApiKey",
   "sentry.AuthProviderDefaultTeams",
-  "sentry.AuthProvider",
   "sentry.ControlFileBlob",
   "sentry.ControlFile",
   "sentry.FileBlob",
@@ -28,21 +25,15 @@
   "sentry.GroupRedirect",
   "sentry.GroupRelease",
   "sentry.Organization",
-  "sentry.Release",
   "sentry.IdentityProvider",
   "sentry.DocIntegration",
-  "sentry.ExternalIssue",
   "sentry.Integration",
   "sentry.IntegrationExternalProject",
   "sentry.IntegrationFeature",
   "sentry.LatestRepoReleaseEnvironment",
   "sentry.User",
-  "sentry.NotificationSetting",
-  "sentry.NotificationSettingOption",
-  "sentry.NotificationSettingProvider",
   "sentry.OrganizationMapping",
   "sentry.OrganizationMemberMapping",
-  "sentry.OrgAuthToken",
   "sentry.SnubaQuery",
   "sentry.SnubaQueryEventType",
   "sentry.Project",
@@ -58,19 +49,13 @@
   "sentry.RecentSearch",
   "sentry.RelayUsage",
   "sentry.Relay",
-  "sentry.ReleaseActivity",
-  "sentry.ReleaseEnvironment",
   "sentry.ReleaseFile",
-  "sentry.ReleaseProjectEnvironment",
   "sentry.Repository",
   "sentry.ReprocessingReport",
-  "sentry.Rule",
-  "sentry.RuleActivity",
   "sentry.SavedSearch",
   "sentry.ScheduledDeletion",
   "sentry.RegionScheduledDeletion",
   "sentry.SentryFunction",
-  "sentry.ServiceHook",
   "sentry.RegionTombstone",
   "sentry.ControlTombstone",
   "sentry.ProjectTransactionThresholdOverride",
@@ -81,12 +66,7 @@
   "sentry.UserReport",
   "sentry.UserRole",
   "sentry.UserRoleUser",
-  "sentry.NotificationAction",
   "sentry.TimeSeriesSnapshot",
-  "sentry.AlertRule",
-  "sentry.AlertRuleTrigger",
-  "sentry.AlertRuleTriggerAction",
-  "sentry.AlertRuleActivity",
   "sentry.DiscoverSavedQuery",
   "sentry.Monitor",
   "sentry.MonitorLocation",
@@ -101,29 +81,21 @@
   "social_auth.UserSocialAuth",
   "sentry.MonitorCheckIn",
   "sentry.DiscoverSavedQueryProject",
-  "sentry.AlertRuleExcludedProjects",
-  "sentry.Incident",
-  "sentry.IncidentSeen",
-  "sentry.IncidentProject",
-  "sentry.NotificationActionProject",
-  "sentry.ServiceHookProject",
-  "sentry.RuleSnooze",
   "sentry.QuerySubscription",
   "sentry.ProcessingIssue",
+  "sentry.OrgAuthToken",
   "sentry.OrganizationOnboardingTask",
   "sentry.LostPasswordHash",
   "sentry.LatestAppConnectBuildsCheck",
-  "sentry.RepositoryProjectPathConfig",
   "sentry.ProjectIntegration",
   "sentry.OrganizationIntegration",
+  "sentry.ExternalIssue",
   "sentry.Identity",
   "sentry.GroupTombstone",
+  "sentry.Release",
   "sentry.ReleaseProject",
   "sentry.OrganizationMember",
-  "sentry.Team",
-  "sentry.OrganizationMemberTeam",
   "sentry.Group",
-  "sentry.GroupHistory",
   "sentry.FeatureAdoption",
   "sentry.EnvironmentProject",
   "sentry.Distribution",
@@ -135,7 +107,6 @@
   "sentry.Commit",
   "sentry.BroadcastSeen",
   "sentry.UserAvatar",
-  "sentry.TeamAvatar",
   "sentry.ProjectAvatar",
   "sentry.OrganizationAvatar",
   "sentry.DocIntegrationAvatar",
@@ -143,14 +114,16 @@
   "sentry.FileBlobOwner",
   "sentry.ControlFileBlobIndex",
   "sentry.ControlFileBlobOwner",
+  "sentry.AuthProvider",
   "sentry.AuthIdentity",
   "sentry.Authenticator",
-  "sentry.AuditLogEntry",
   "sentry.AssistantActivity",
   "sentry.ArtifactBundleFlatFileIndex",
   "sentry.ArtifactBundle",
   "sentry.AppConnectBuild",
+  "sentry.ApiKey",
   "sentry.ApiApplication",
+  "sentry.Actor",
   "sentry.UserOption",
   "sentry.ProjectOption",
   "sentry.OrganizationOption",
@@ -163,10 +136,10 @@
   "sentry.ReleaseArtifactBundle",
   "sentry.DebugIdArtifactBundle",
   "sentry.ProjectArtifactBundle",
+  "sentry.AuditLogEntry",
   "sentry.CommitFileChange",
   "sentry.DashboardWidget",
-  "sentry.GroupOwner",
-  "sentry.GroupAssignee",
+  "sentry.GroupHistory",
   "sentry.GroupBookmark",
   "sentry.GroupEmailThread",
   "sentry.GroupEnvironment",
@@ -174,34 +147,61 @@
   "sentry.GroupInbox",
   "sentry.GroupLink",
   "sentry.GroupMeta",
+  "sentry.Team",
   "sentry.GroupResolution",
-  "sentry.GroupRuleStatus",
   "sentry.GroupSeen",
   "sentry.GroupShare",
   "sentry.GroupSnooze",
   "sentry.GroupSubscription",
   "sentry.ExternalActor",
   "sentry.SentryApp",
+  "sentry.RepositoryProjectPathConfig",
   "sentry.SentryAppComponent",
   "sentry.SentryAppInstallation",
   "sentry.SentryAppInstallationForProvider",
   "sentry.SentryAppInstallationToken",
+  "sentry.NotificationSetting",
+  "sentry.NotificationSettingOption",
+  "sentry.NotificationSettingProvider",
   "sentry.OrganizationAccessRequest",
   "sentry.PlatformExternalIssue",
   "sentry.EventProcessingIssue",
   "sentry.ProjectTeam",
   "sentry.ProjectCodeOwners",
   "sentry.PullRequestCommit",
+  "sentry.ReleaseActivity",
   "sentry.ReleaseCommit",
+  "sentry.ReleaseEnvironment",
   "sentry.ReleaseHeadCommit",
+  "sentry.ReleaseProjectEnvironment",
+  "sentry.Rule",
+  "sentry.RuleActivity",
   "sentry.RuleFireHistory",
+  "sentry.ServiceHook",
+  "sentry.NotificationAction",
+  "sentry.AlertRule",
+  "sentry.AlertRuleTrigger",
+  "sentry.AlertRuleTriggerExclusion",
+  "sentry.AlertRuleTriggerAction",
+  "sentry.AlertRuleActivity",
+  "sentry.TeamKeyTransaction",
+  "sentry.AlertRuleExcludedProjects",
+  "sentry.Incident",
+  "sentry.IncidentSeen",
+  "sentry.IncidentProject",
+  "sentry.NotificationActionProject",
+  "sentry.ServiceHookProject",
+  "sentry.RuleSnooze",
+  "sentry.GroupRuleStatus",
+  "sentry.OrganizationMemberTeam",
+  "sentry.GroupAssignee",
+  "sentry.GroupOwner",
+  "sentry.DashboardWidgetQuery",
+  "sentry.TeamAvatar",
+  "sentry.SentryAppAvatar",
   "sentry.PendingIncidentSnapshot",
   "sentry.IncidentSnapshot",
   "sentry.IncidentActivity",
   "sentry.IncidentSubscription",
-  "sentry.IncidentTrigger",
-  "sentry.AlertRuleTriggerExclusion",
-  "sentry.TeamKeyTransaction",
-  "sentry.DashboardWidgetQuery",
-  "sentry.SentryAppAvatar"
+  "sentry.IncidentTrigger"
 ]

+ 8 - 6
src/sentry/backup/dependencies.py

@@ -124,13 +124,14 @@ def dependencies() -> dict[str, ModelRelations]:
         if app_config.label in EXCLUDED_APPS:
             continue
 
+        models_from_names = {model._meta.object_name: model for model in app_config.get_models()}
         model_iterator = app_config.get_models()
 
         for model in model_iterator:
             foreign_keys: dict[str, ForeignField] = dict()
 
             # Now add a dependency for any FK relation with a model that defines a natural key.
-            for field in model._meta.fields:
+            for field in model._meta.get_fields():
                 rel_model = getattr(field.remote_field, "model", None)
                 if rel_model is not None and rel_model != model:
                     # TODO(hybrid-cloud): actor refactor.
@@ -144,16 +145,17 @@ def dependencies() -> dict[str, ModelRelations]:
                             model=rel_model,
                             kind=ForeignFieldKind.FlexibleForeignKey,
                         )
-                    elif isinstance(field, HybridCloudForeignKey):
-                        foreign_keys[field.name] = ForeignField(
-                            model=rel_model,
-                            kind=ForeignFieldKind.HybridCloudForeignKey,
-                        )
                     elif isinstance(field, ForeignKey):
                         foreign_keys[field.name] = ForeignField(
                             model=rel_model,
                             kind=ForeignFieldKind.DefaultForeignKey,
                         )
+                elif isinstance(field, HybridCloudForeignKey):
+                    rel_model = models_from_names[field.foreign_model_name[7:]]
+                    foreign_keys[field.name] = ForeignField(
+                        model=rel_model,
+                        kind=ForeignFieldKind.HybridCloudForeignKey,
+                    )
 
             # Get all simple O2O relations as well.
             one_to_one_fields = [

+ 1 - 1
src/sentry/backup/imports.py

@@ -53,7 +53,7 @@ def imports(src, old_config: OldImportConfig, printer=click.echo):
                         label = o._meta.label_lower
                         model_name = normalize_model_name(o)
                         for field, model_relation in deps[model_name].foreign_keys.items():
-                            field_id = f"{field}_id"
+                            field_id = field if field.endswith("_id") else f"{field}_id"
                             fk = getattr(o, field_id, None)
                             if fk is not None:
                                 new_pk = pk_map.get(normalize_model_name(model_relation.model), fk)

+ 9 - 13
tests/sentry/backup/test_models.py

@@ -24,7 +24,7 @@ from sentry.incidents.models import (
     PendingIncidentSnapshot,
     TimeSeriesSnapshot,
 )
-from sentry.models.actor import ACTOR_TYPES, Actor
+from sentry.models.actor import Actor
 from sentry.models.apiapplication import ApiApplication
 from sentry.models.apiauthorization import ApiAuthorization
 from sentry.models.apikey import ApiKey
@@ -210,6 +210,7 @@ class ModelBackupTests(TransactionTestCase):
     @targets(mark(AuthIdentity, AuthProvider))
     def test_auth_identity_provider(self):
         user = self.create_user()
+        org = self.create_organization(owner=user)
         test_data = {
             "key1": "value1",
             "key2": 42,
@@ -218,7 +219,7 @@ class ModelBackupTests(TransactionTestCase):
         }
         AuthIdentity.objects.create(
             user=user,
-            auth_provider=AuthProvider.objects.create(organization_id=1, provider="sentry"),
+            auth_provider=AuthProvider.objects.create(organization_id=org.id, provider="sentry"),
             ident="123456789",
             data=test_data,
         )
@@ -470,9 +471,7 @@ class ModelBackupTests(TransactionTestCase):
     @targets(mark(SentryApp, SentryAppComponent, SentryAppInstallation))
     def test_sentry_app(self):
         app = self.create_sentry_app(name="test_app", organization=self.organization)
-        self.create_sentry_app_installation(
-            slug=app.slug, organization=self.organization, user=self.user
-        )
+        self.create_sentry_app_installation(slug=app.slug, organization=self.organization)
         updater = SentryAppUpdater(sentry_app=app)
         updater.schema = {"elements": [self.create_alert_rule_action_schema()]}
         updater.run(self.user)
@@ -489,16 +488,13 @@ class ModelBackupTests(TransactionTestCase):
     @targets(mark(ServiceHook))
     def test_service_hook(self):
         app = self.create_sentry_app()
-        actor = Actor.objects.create(type=ACTOR_TYPES["team"])
         install = self.create_sentry_app_installation(organization=self.organization, slug=app.slug)
-        ServiceHook.objects.create(
-            application_id=app.id,
-            actor_id=actor.id,
-            project_id=self.project.id,
-            organization_id=self.organization.id,
-            events=[],
+        self.create_service_hook(
+            application_id=app.application.id,
+            actor_id=app.proxy_user.id,
             installation_id=install.id,
-            url="https://example.com",
+            project=self.project,
+            org=self.project.organization,
         )
         return self.import_export_then_validate()