Skip to content

[management] update account delete with proper proxy domain and service cleanup#5817

Merged
pascal-fischer merged 5 commits intomainfrom
fix/proxy-cleanup-on-account-delete
Apr 10, 2026
Merged

[management] update account delete with proper proxy domain and service cleanup#5817
pascal-fischer merged 5 commits intomainfrom
fix/proxy-cleanup-on-account-delete

Conversation

@pascal-fischer
Copy link
Copy Markdown
Collaborator

@pascal-fischer pascal-fischer commented Apr 7, 2026

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • New Features

    • Accounts can now be associated with custom proxied domains.
  • Refactor

    • Account deletion now ensures associated service and domain records are removed as part of the deletion process, improving cleanup consistency.
  • Tests

    • Tests and benchmarks updated to include the domain model and to verify that services and custom domains are cleaned up when an account is deleted.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 7, 2026

📝 Walkthrough

Walkthrough

Removed the application-layer bulk service deletion call from DefaultAccountManager.DeleteAccount; SqlStore.DeleteAccount now deletes account.Services in-transaction. Added a GORM Domains []*proxydomain.Domain association and associated copy logic, and updated tests/benchmarks to include Domain model.

Changes

Cohort / File(s) Summary
Account manager
management/server/account.go
Removed call to am.serviceManager.DeleteAllServices(ctx, accountID, userID) from DefaultAccountManager.DeleteAccount; now deletes users and account without prior bulk service deletion.
SQL store
management/server/store/sql_store.go
Added explicit in-transaction deletion of account.Services (Delete(account.Services, "account_id = ?")) before deleting the account record; errors are propagated immediately.
Account model
management/server/types/account.go
Added Domains []*proxydomain.Domain GORM association to Account and updated Account.Copy() to deep-copy Domains.
Domain model
management/internals/modules/reverseproxy/domain/domain.go
Added Copy() *Domain method that returns a shallow copy of a Domain.
Tests / Benchmarks
management/server/store/sqlstore_bench_test.go, management/server/account_test.go, management/server/store/sql_store_test.go
Included reverseproxy/domain.Domain in benchmark migrations; updated account tests to populate Domains; extended DeleteAccount tests to seed and assert cleanup of reverse-proxy Service/Target and Domain rows.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant AccountManager as DefaultAccountManager
participant ServiceManager
participant SQLStore
participant DB as Database

rect rgba(200,200,255,0.5)
Note over Client,AccountManager: OLD FLOW
Client->>AccountManager: DeleteAccount(accountID, userID)
AccountManager->>ServiceManager: DeleteAllServices(ctx, accountID, userID)
ServiceManager->>DB: delete services by account_id
ServiceManager-->>AccountManager: result
AccountManager->>SQLStore: DeleteAccount(tx, account)
SQLStore->>DB: delete account (and associations)
SQLStore-->>AccountManager: result
end

rect rgba(200,255,200,0.5)
Note over Client,AccountManager: NEW FLOW
Client->>AccountManager: DeleteAccount(accountID, userID)
AccountManager->>SQLStore: DeleteAccount(tx, account) -- deletes account.Services in tx
SQLStore->>DB: delete account.Services where account_id=...
SQLStore->>DB: delete account
SQLStore-->>AccountManager: result
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • bcmmbaga
  • mlsmaycon

Poem

🐰 I hop through rows and tidy seeds,

Services moved where DB now leads,
Domains tucked in careful rows,
Transactions hum as cleanup goes,
A carrot commit — and off I speed!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete. While the author filled in the template structure and correctly marked this as a bug fix with no documentation needed, the 'Describe your changes' section is empty, providing no explanation of what was changed or why. Fill in the 'Describe your changes' section with details about the modifications to account deletion logic and the addition of domain/service cleanup. Optionally add an issue ticket reference if available.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: updating account deletion logic to include proper cleanup of proxy domains and services.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/proxy-cleanup-on-account-delete

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
management/server/types/account.go (1)

105-105: Consider enforcing DB-level cleanup for Domains association.

At Line 105, Domains is a new account-scoped relation, but the tag does not enforce cascade deletion. Adding an explicit constraint makes account cleanup resilient even if delete paths change later.

♻️ Suggested hardening
-	Domains                []*proxydomain.Domain             `gorm:"foreignKey:AccountID;references:id"`
+	Domains                []*proxydomain.Domain             `gorm:"foreignKey:AccountID;references:id;constraint:OnDelete:CASCADE"`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/types/account.go` at line 105, The Domains association on
the Account model lacks a DB-level cascade constraint; update the Domains field
tag (on the Account struct) to include a GORM constraint that enforces cascade
delete (and optionally cascade update) so associated proxydomain.Domain rows are
removed when an Account is deleted (e.g., add a gorm tag like
`constraint:OnDelete:CASCADE,OnUpdate:CASCADE` to the Domains field).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@management/server/store/sql_store.go`:
- Around line 399-404: The transaction that removes an Account (in
DeleteAccount) currently deletes Services, Policies, and UsersG but omits
Domains, leaving orphaned Domain rows; add an explicit deletion of
account.Domains via the same tx.Select(clause.Associations).Delete(...) pattern
(filtering by account.Id or account_id) before the final tx.Delete(account) so
Domains are removed in the same transaction; update the DeleteAccount
transaction to call the deletion for account.Domains (similar to how
account.Services is deleted) and check/return result.Error as done for the other
deletes.

---

Nitpick comments:
In `@management/server/types/account.go`:
- Line 105: The Domains association on the Account model lacks a DB-level
cascade constraint; update the Domains field tag (on the Account struct) to
include a GORM constraint that enforces cascade delete (and optionally cascade
update) so associated proxydomain.Domain rows are removed when an Account is
deleted (e.g., add a gorm tag like
`constraint:OnDelete:CASCADE,OnUpdate:CASCADE` to the Domains field).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b53b58b4-cc0b-4ef8-bde6-73e8e6df0c68

📥 Commits

Reviewing files that changed from the base of the PR and between 0588d2d and 34e720b.

📒 Files selected for processing (3)
  • management/server/account.go
  • management/server/store/sql_store.go
  • management/server/types/account.go
💤 Files with no reviewable changes (1)
  • management/server/account.go

Comment on lines +399 to 404
result = tx.Select(clause.Associations).Delete(account.Services, "account_id = ?", account.Id)
if result.Error != nil {
return result.Error
}

result = tx.Select(clause.Associations).Delete(account)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Account model associations =="
rg -n 'Services\s+\[\]\*service\.Service|Domains\s+\[\]\*proxydomain\.Domain' management/server/types/account.go

echo
echo "== Domain model delete constraint check =="
rg -n 'type Domain struct|AccountID|constraint|OnDelete' management/internals/modules/reverseproxy/domain/domain.go -A8 -B2

echo
echo "== DeleteAccount cleanup steps =="
rg -n 'func \(s \*SqlStore\) DeleteAccount|Delete\(account\.Policies|Delete\(account\.UsersG|Delete\(account\.Services|Delete\(account\.Domains|Delete\(account\)' management/server/store/sql_store.go -A30 -B5

Repository: netbirdio/netbird

Length of output: 4423


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full DeleteAccount function context =="
sed -n '385,419p' management/server/store/sql_store.go

echo
echo "== Checking for any domain cleanup elsewhere =="
rg -n 'Domains.*Delete|DeleteDomain|domain.*orphan|cascade.*domain' management/server/store/sql_store.go

echo
echo "== Checking Account model for Domains association details =="
sed -n '100,110p' management/server/types/account.go

echo
echo "== Checking if there are transaction hooks or other cleanup paths =="
rg -n 'func.*Delete|OnDelete|cascade' management/internals/modules/reverseproxy/domain/domain.go

Repository: netbirdio/netbird

Length of output: 1117


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Checking cascade delete behavior in other delete operations =="
rg -n 'Select\(clause\.Associations\)\.Delete' management/server/store/sql_store.go -B2 -A2

echo
echo "== Looking for account deletion tests =="
fd -t f '.*test.*\.go$' | xargs rg -l 'DeleteAccount' | head -5

echo
echo "== Checking if Domains have any cascade constraints defined =="
rg -n 'type Domain struct' management/internals/modules/reverseproxy/domain/domain.go -A30 | head -40

echo
echo "== Checking recent changes or migrations related to domains =="
fd -t f '*.go' management/server/store | xargs rg -l 'Domain' | grep -i migrat

Repository: netbirdio/netbird

Length of output: 2975


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== DeleteAccount test cases =="
rg -n 'DeleteAccount|func Test.*Delete' management/server/store/sql_store_test.go -A20 | head -80

echo
echo "== Domain-related assertions in tests =="
rg -n 'Domain.*assert|assert.*Domain|orphan' management/server/store/sql_store_test.go

echo
echo "== Check if Domains cleanup is tested =="
rg -n 'Domains|proxydomain' management/server/store/sql_store_test.go | head -10

Repository: netbirdio/netbird

Length of output: 4631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check if there's a test for domain orphaning (searching for domain-related test) =="
rg -n 'Domain|proxydomain' management/server/store/sql_store_test.go -B2 -A5 | grep -A5 -B5 'Delete'

echo
echo "== Looking for any domain cleanup or cascading logic =="
rg -n 'type Account struct' management/server/types/account.go -A50 | grep -E 'Domains|Services'

echo
echo "== Checking if there are database migrations or constraints for domains =="
fd -t f 'migrat' management/server/store | xargs cat 2>/dev/null | grep -i 'domain\|account_id' | head -20

Repository: netbirdio/netbird

Length of output: 1384


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Finding migration/schema files =="
find . -type f \( -name '*migrat*' -o -name '*.sql' \) | grep -v node_modules | grep -v '.git' | head -20

echo
echo "== Checking if GORM cascade delete works with the foreignKey pattern =="
rg -n 'onDelete|ON DELETE|cascade' management/server/types/ management/internals/modules/reverseproxy/domain/

echo
echo "== Looking for when Services deletion was added (search for Services delete pattern) =="
rg -n 'Delete\(account\.Services' management/server/store/sql_store.go -B10 -A5

Repository: netbirdio/netbird

Length of output: 1205


🏁 Script executed:

#!/bin/bash
set -euco pipefail

echo "== Checking migration.go for domain table definition =="
cat management/server/store/migration.go | grep -A20 'type domains\|Domain table' || echo "Searching differently..."

echo
echo "== Searching for Domain table creation in migrations =="
rg -n 'CreateTable.*domain\|domains.*table' management/server/store/ -i

echo
echo "== Checking GORM migration syntax for cascade constraints =="
rg -n 'ForeignKey.*onDelete|OnDelete\|constraint' management/server/store/migration.go -B2 -A2

echo
echo "== Looking at how Services table is created vs Domains =="
rg -n 'CreateTable.*service\|CreateTable.*domain' management/server/store/migration.go -i -A10 | head -50

Repository: netbirdio/netbird

Length of output: 677


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Checking migration_up.go =="
ls -la management/cmd/migration_up.go && wc -l management/cmd/migration_up.go

echo
echo "== Searching for Domain table AutoMigrate in store code =="
rg -n 'AutoMigrate.*Domain\|Domain.*AutoMigrate' management/server/store/ -B2 -A2

echo
echo "== Looking for main store initialization =="
rg -n 'func.*New.*SqlStore\|AutoMigrate' management/server/store/sql_store.go -A30 | head -60

echo
echo "== Finding where models are migrated =="
fd -t f 'sql_store.go' management/server/store/ | xargs rg -n 'AutoMigrate' -B5 -A10

Repository: netbirdio/netbird

Length of output: 265


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Checking how db is initialized and tables created =="
rg -n 'func.*Open.*\|gorm\.Open\|AutoMigrate\|CreateTable' management/server/store/sqlite.go -B2 -A8 | head -80

echo
echo "== Looking for all GORM model tags for Account associations =="
rg -n 'Services.*gorm\|Domains.*gorm' management/server/types/account.go -B1 -A1

echo
echo "== Checking if there are onDelete tags on the Domain or Service models =="
rg -n 'onDelete\|OnDelete' management/server/types/ management/internals/modules/reverseproxy/ -i

Repository: netbirdio/netbird

Length of output: 207


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== List files in store directory =="
ls -la management/server/store/ | grep -E '\.go$|^total'

echo
echo "== Find where DB tables are created/migrated =="
rg -n 'gorm\.DB\|Migrator\|CreateTable' management/server/store/*.go | head -30

echo
echo "== Check if GORM's Select(clause.Associations) cascades on Account.Domains =="
rg -n 'Select\(clause\.Associations\)\.Delete' management/server/store/*.go -B5 -A5

Repository: netbirdio/netbird

Length of output: 867


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Looking at sql_store.go initialization =="
head -100 management/server/store/sql_store.go

echo
echo "== Searching for how DB handles cascade deletes in current code =="
rg -n 'Select\(clause\.Associations\)|clause\.Associations' management/server/store/sql_store.go

echo
echo "== Check the Account model associations more carefully =="
sed -n '95,115p' management/server/types/account.go

Repository: netbirdio/netbird

Length of output: 6699


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check constraint tags on Account associations =="
rg -n 'gorm:' management/server/types/account.go | grep -E 'Services|Domains|Policies|Users|Onboarding'

echo
echo "== Check if Domain cleanup is actually tested =="
rg -n 'GetDomain\|proxydomain\|Domains' management/server/store/sql_store_test.go | grep -i 'delete\|account'

echo
echo "== Verify if domains would be orphaned after account deletion =="
rg -n 'Domains\|domain.*delete\|orphan' management/server/store/sql_store_test.go

Repository: netbirdio/netbird

Length of output: 792


Add explicit Domain deletion in DeleteAccount transaction.

Lines 399-404 clean up Services, Policies, and UsersG before deleting the account, but Domains are missing. Without the OnDelete:CASCADE constraint (unlike Onboarding), Domain rows will be orphaned when the account is deleted.

Proposed fix
		result = tx.Select(clause.Associations).Delete(account.Services, "account_id = ?", account.Id)
		if result.Error != nil {
			return result.Error
		}

+		result = tx.Select(clause.Associations).Delete(account.Domains, "account_id = ?", account.Id)
+		if result.Error != nil {
+			return result.Error
+		}
+
		result = tx.Select(clause.Associations).Delete(account)
		if result.Error != nil {
			return result.Error
		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
result = tx.Select(clause.Associations).Delete(account.Services, "account_id = ?", account.Id)
if result.Error != nil {
return result.Error
}
result = tx.Select(clause.Associations).Delete(account)
result = tx.Select(clause.Associations).Delete(account.Services, "account_id = ?", account.Id)
if result.Error != nil {
return result.Error
}
result = tx.Select(clause.Associations).Delete(account.Domains, "account_id = ?", account.Id)
if result.Error != nil {
return result.Error
}
result = tx.Select(clause.Associations).Delete(account)
if result.Error != nil {
return result.Error
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/store/sql_store.go` around lines 399 - 404, The transaction
that removes an Account (in DeleteAccount) currently deletes Services, Policies,
and UsersG but omits Domains, leaving orphaned Domain rows; add an explicit
deletion of account.Domains via the same
tx.Select(clause.Associations).Delete(...) pattern (filtering by account.Id or
account_id) before the final tx.Delete(account) so Domains are removed in the
same transaction; update the DeleteAccount transaction to call the deletion for
account.Domains (similar to how account.Services is deleted) and check/return
result.Error as done for the other deletes.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
management/server/store/sqlstore_bench_test.go (1)

262-270: Consider seeding at least one Domain row to exercise this schema path.

Line 269 correctly adds &domain.Domain{} to migration setup. As a follow-up, add a minimal Domain fixture and equivalence assertion so this change is behaviorally covered (not just schema-present).

Suggested follow-up (example)
 const (
   accountID           = "benchmark-account-id"
+  domainID            = "benchmark-domain-id"
   numUsers            = 20
   ...
 )

 ...

 if err := db.Create(&acc).Error; err != nil {
   b.Fatalf("create account: %v", err)
 }

+dom := domain.Domain{
+  ID:        domainID,
+  AccountID: accountID,
+  Domain:    "svc.benchmark.com",
+}
+if err := db.Create(&dom).Error; err != nil {
+  b.Fatalf("create domain: %v", err)
+}

And in testAccountEquivalence(...), add a Domains equality check once domain fixtures are present.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/store/sqlstore_bench_test.go` around lines 262 - 270, Add a
minimal Domain fixture to the migration/seed dataset so the Domain schema path
is exercised: include a populated instance (e.g. with Name/AccountID or other
required fields) alongside the existing &domain.Domain{} entry in the
models/seed setup, and update the testAccountEquivalence(...) assertions to
compare Domains as well (add a Domains equality check or include Domain fields
in the existing account equivalence check) so the new Domain row is behaviorally
validated rather than only present in the schema.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@management/server/store/sqlstore_bench_test.go`:
- Around line 262-270: Add a minimal Domain fixture to the migration/seed
dataset so the Domain schema path is exercised: include a populated instance
(e.g. with Name/AccountID or other required fields) alongside the existing
&domain.Domain{} entry in the models/seed setup, and update the
testAccountEquivalence(...) assertions to compare Domains as well (add a Domains
equality check or include Domain fields in the existing account equivalence
check) so the new Domain row is behaviorally validated rather than only present
in the schema.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2837277c-527f-4894-9622-764b7a1b85fd

📥 Commits

Reviewing files that changed from the base of the PR and between 34e720b and 15d3043.

📒 Files selected for processing (1)
  • management/server/store/sqlstore_bench_test.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
management/server/account_test.go (1)

1820-1826: Consider extending this test to assert domain pointer-field copy isolation.

This fixture is a great start; adding assertions for SupportsCustomPorts / RequireSubdomain would catch aliasing regressions in Domain.Copy().

Possible test enhancement
+	supportsCustomPorts := true
+	requireSubdomain := true
 	account := &types.Account{
@@
 		Domains: []*domain.Domain{
 			{
 				ID:        "domain1",
 				Domain:    "test.com",
 				AccountID: "account1",
+				SupportsCustomPorts: &supportsCustomPorts,
+				RequireSubdomain:    &requireSubdomain,
 			},
 		},
@@
 	accountCopy := account.Copy()
@@
+	*account.Domains[0].SupportsCustomPorts = false
+	*account.Domains[0].RequireSubdomain = false
+	require.True(t, *accountCopy.Domains[0].SupportsCustomPorts)
+	require.True(t, *accountCopy.Domains[0].RequireSubdomain)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/account_test.go` around lines 1820 - 1826, Extend the test
fixture to verify Domain.Copy() creates independent pointer-field copies by: for
each domain in the fixture call copied := domain.Copy(), assert
copied.SupportsCustomPorts and copied.RequireSubdomain match the original
values, then mutate the original domain's SupportsCustomPorts and
RequireSubdomain and assert the copied values do not change (and vice versa);
use the Domain.Copy() helper and the SupportsCustomPorts/RequireSubdomain fields
to locate the code and ensure no aliasing between original and copied pointer
fields.
management/server/types/account.go (1)

916-919: Optional: preallocate domains slice capacity.

Tiny improvement for large accounts:

Suggested micro-refactor
-	domains := []*proxydomain.Domain{}
+	domains := make([]*proxydomain.Domain, 0, len(a.Domains))
 	for _, domain := range a.Domains {
 		domains = append(domains, domain.Copy())
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/types/account.go` around lines 916 - 919, The loop building
domains currently appends into an empty slice which causes reallocations for
large accounts; preallocate the slice capacity using make with length or
capacity based on len(a.Domains) (e.g., initialize domains :=
make([]*proxydomain.Domain, 0, len(a.Domains))) and then append each
domain.Copy() from a.Domains (symbols: domains, a.Domains, Domain.Copy()) so the
slice grows without repeated allocations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@management/server/account_test.go`:
- Around line 1820-1826: Extend the test fixture to verify Domain.Copy() creates
independent pointer-field copies by: for each domain in the fixture call copied
:= domain.Copy(), assert copied.SupportsCustomPorts and copied.RequireSubdomain
match the original values, then mutate the original domain's SupportsCustomPorts
and RequireSubdomain and assert the copied values do not change (and vice
versa); use the Domain.Copy() helper and the
SupportsCustomPorts/RequireSubdomain fields to locate the code and ensure no
aliasing between original and copied pointer fields.

In `@management/server/types/account.go`:
- Around line 916-919: The loop building domains currently appends into an empty
slice which causes reallocations for large accounts; preallocate the slice
capacity using make with length or capacity based on len(a.Domains) (e.g.,
initialize domains := make([]*proxydomain.Domain, 0, len(a.Domains))) and then
append each domain.Copy() from a.Domains (symbols: domains, a.Domains,
Domain.Copy()) so the slice grows without repeated allocations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: de4a2abf-ac4c-4eca-af83-1f83aaaef758

📥 Commits

Reviewing files that changed from the base of the PR and between 15d3043 and 8f973d2.

📒 Files selected for processing (3)
  • management/internals/modules/reverseproxy/domain/domain.go
  • management/server/account_test.go
  • management/server/types/account.go

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
management/server/store/sql_store_test.go (1)

446-458: Add Postgres parity for the new cleanup assertions.

Line 446 onward validates domain/service/target cleanup only in TestSqlite_DeleteAccount. Please mirror this in TestPostgresql_DeleteAccount so cross-engine delete behavior is guarded too.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@management/server/store/sql_store_test.go` around lines 446 - 458, The
Postgres test TestPostgresql_DeleteAccount is missing the cleanup assertions
added to TestSqlite_DeleteAccount: after DeleteAccount call, call
store.ListCustomDomains(ctx, account.Id) and assert no error and zero length,
then query the underlying SqlStore db for rpservice.Service and rpservice.Target
(using db.Model(&rpservice.Service{}).Find(&services, "account_id = ?",
account.Id).Error and similarly for rpservice.Target) and assert no error and
length 0 for each; mirror the exact checks from TestSqlite_DeleteAccount into
TestPostgresql_DeleteAccount to ensure parity across engines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@management/server/store/sql_store_test.go`:
- Around line 446-458: The Postgres test TestPostgresql_DeleteAccount is missing
the cleanup assertions added to TestSqlite_DeleteAccount: after DeleteAccount
call, call store.ListCustomDomains(ctx, account.Id) and assert no error and zero
length, then query the underlying SqlStore db for rpservice.Service and
rpservice.Target (using db.Model(&rpservice.Service{}).Find(&services,
"account_id = ?", account.Id).Error and similarly for rpservice.Target) and
assert no error and length 0 for each; mirror the exact checks from
TestSqlite_DeleteAccount into TestPostgresql_DeleteAccount to ensure parity
across engines.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5d90f8bd-517b-40d1-990a-ed03449c447f

📥 Commits

Reviewing files that changed from the base of the PR and between 8f973d2 and 93fc09a.

📒 Files selected for processing (1)
  • management/server/store/sql_store_test.go

@pascal-fischer pascal-fischer merged commit 15709bc into main Apr 10, 2026
45 of 46 checks passed
@pascal-fischer pascal-fischer deleted the fix/proxy-cleanup-on-account-delete branch April 10, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants