fix(user-deletion): safely clean up team-owned Git app sources#9435
fix(user-deletion): safely clean up team-owned Git app sources#9435andrasbacsai merged 6 commits intonextfrom
Conversation
Limit team cleanup to apps owned by the deleted team and nullify cross-team application source references before deleting team-owned sources. Adds feature tests covering user deletion with GitHub app-backed applications, preserving system-wide apps, and nullifying external source links.
|
Hey @andrasbacsai this looks good for the The new source-nullification logic lives in Would it make sense to move the source-detach/nullify step into I could 100% be wrong, you do know the code much, much better than I ever will. Here is my suggested fix. protected static function booted()
{
static::created(function ($team) {
$team->emailNotificationSettings()->create([
'use_instance_email_settings' => isDev(),
]);
$team->discordNotificationSettings()->create();
$team->slackNotificationSettings()->create();
$team->telegramNotificationSettings()->create();
$team->pushoverNotificationSettings()->create();
$team->webhookNotificationSettings()->create();
});
static::saving(function ($team) {
if (auth()->user()?->isMember()) {
throw new \Exception('You are not allowed to update this team.');
}
});
static::deleting(function (Team $team) {
$team->detachSourceReferences();
foreach ($team->privateKeys as $key) {
$key->delete();
}
// Only delete sources owned by this team, not system-wide ones from other teams.
$teamSources = GithubApp::where('team_id', $team->id)->get()
->merge(GitlabApp::where('team_id', $team->id)->get());
foreach ($teamSources as $source) {
$source->delete();
}
foreach (Tag::whereTeamId($team->id)->get() as $tag) {
$tag->delete();
}
foreach ($team->environment_variables()->get() as $sharedVariable) {
$sharedVariable->delete();
}
foreach ($team->s3s as $s3) {
$s3->delete();
}
});
}
private function detachSourceReferences(): void
{
$githubAppIds = GithubApp::where('team_id', $this->id)->pluck('id');
if ($githubAppIds->isNotEmpty()) {
Application::where('source_type', GithubApp::class)
->whereIn('source_id', $githubAppIds)
->update([
'source_id' => null,
'source_type' => null,
]);
}
$gitlabAppIds = GitlabApp::where('team_id', $this->id)->pluck('id');
if ($gitlabAppIds->isNotEmpty()) {
Application::where('source_type', GitlabApp::class)
->whereIn('source_id', $gitlabAppIds)
->update([
'source_id' => null,
'source_type' => null,
]);
}
} |
Instead of nullifying source references on applications when a team is deleted, transfer instance-wide GitHub/GitLab apps to the root team (team_id=0) so they remain available to other teams that depend on them. Non-instance-wide sources are still deleted along with the team.
Summary
Teamdeletion.applications.source_id/source_typereferences (for GitHub/GitLab app sources) that point to the soon-to-be-deleted team-owned sources, avoiding guard exceptions.Breaking Changes
Fixes #8172