What
VaultService._name_and_slug_provider_key picks an unnamed connection's display name ("OpenAI", then "OpenAI 2") by listing the project's existing secrets and choosing the first free name, then creates the record in a separate DAO session. header.name has no uniqueness constraint, so two concurrent unnamed creates for the same provider family can both read the same taken_names and both persist "OpenAI".
Reported by CodeRabbit on PR #5995.
Why it is not urgent
The display name is cosmetic. Identity is the slug (get_slug_from_name_and_id(name, uuid4())), which is project-unique by constraint and is what every resolver addresses a connection by — so a duplicate name cannot cross credentials or make a connection unreachable. The user sees two rows both called "OpenAI" and can rename one.
Why it is not a one-line fix
Closing the window means either serializing name allocation and creation in one transaction (the service currently crosses two DAO sessions, and the DAO owns its session) or adding a DB-backed reservation with retry on conflict. Both change the service/DAO seam for a cosmetic field, which is more than the review that found it should carry.
Suggested shape
- A postgres advisory lock keyed on
(project_id, provider_kind) around list+create, or
- a partial unique index on
(project_id, header.name) for provider_key rows plus a bounded retry that re-derives the next free name on conflict.
Either way, add a concurrent-create test that drives two create_secret calls against one project and asserts two distinct names.
What
VaultService._name_and_slug_provider_keypicks an unnamed connection's display name ("OpenAI", then "OpenAI 2") by listing the project's existing secrets and choosing the first free name, then creates the record in a separate DAO session.header.namehas no uniqueness constraint, so two concurrent unnamed creates for the same provider family can both read the sametaken_namesand both persist "OpenAI".Reported by CodeRabbit on PR #5995.
Why it is not urgent
The display name is cosmetic. Identity is the slug (
get_slug_from_name_and_id(name, uuid4())), which is project-unique by constraint and is what every resolver addresses a connection by — so a duplicate name cannot cross credentials or make a connection unreachable. The user sees two rows both called "OpenAI" and can rename one.Why it is not a one-line fix
Closing the window means either serializing name allocation and creation in one transaction (the service currently crosses two DAO sessions, and the DAO owns its session) or adding a DB-backed reservation with retry on conflict. Both change the service/DAO seam for a cosmetic field, which is more than the review that found it should carry.
Suggested shape
(project_id, provider_kind)around list+create, or(project_id, header.name)forprovider_keyrows plus a bounded retry that re-derives the next free name on conflict.Either way, add a concurrent-create test that drives two
create_secretcalls against one project and asserts two distinct names.