Description
AttributeEngine.registerAttributeContentItems resolves each content item with findByJsonAndAttributeDefinitionUuid and inserts when the lookup returns null, with nothing guarding the gap between the two. This is the same check-then-insert shape as the discovery-import defect fixed in #1897, one layer down.
It is reachable concurrently: discovery post-processing runs several certificate imports in parallel, each applying per-row metadata through the attribute engine, so two of them can register the same not-yet-registered content item at once. The window is narrow because the discovery download phase pre-registers most content items, but it is not closed.
The outcome depends on whether the table carries a unique constraint on (json, attribute_definition_uuid):
Confirming which applies is the first step.
This is pre-existing rather than introduced by #1897; that work only made the pattern easier to see.
Severity
Minor
Steps to Reproduce
- Run a discovery whose certificates carry a metadata attribute value not yet registered for its definition.
- Ensure several discovered certificates share that value, so parallel imports register it concurrently.
- Observe either a duplicate
attribute_content_item row for one definition, or a discovery certificate rolled back with a generic transaction-rollback reason.
Expected
Concurrent registration of the same content item resolves to one row, and no caller's transaction is poisoned by losing the race.
Actual
The gap between the lookup and the insert is unguarded, so concurrent callers either duplicate the row or one of them poisons its own transaction.
Environment
Reachable from discovery post-processing on any release carrying the parallel import path.
Description
AttributeEngine.registerAttributeContentItemsresolves each content item withfindByJsonAndAttributeDefinitionUuidand inserts when the lookup returns null, with nothing guarding the gap between the two. This is the same check-then-insert shape as the discovery-import defect fixed in #1897, one layer down.It is reachable concurrently: discovery post-processing runs several certificate imports in parallel, each applying per-row metadata through the attribute engine, so two of them can register the same not-yet-registered content item at once. The window is narrow because the discovery download phase pre-registers most content items, but it is not closed.
The outcome depends on whether the table carries a unique constraint on
(json, attribute_definition_uuid):Confirming which applies is the first step.
This is pre-existing rather than introduced by #1897; that work only made the pattern easier to see.
Severity
Minor
Steps to Reproduce
attribute_content_itemrow for one definition, or a discovery certificate rolled back with a generic transaction-rollback reason.Expected
Concurrent registration of the same content item resolves to one row, and no caller's transaction is poisoned by losing the race.
Actual
The gap between the lookup and the insert is unguarded, so concurrent callers either duplicate the row or one of them poisons its own transaction.
Environment
Reachable from discovery post-processing on any release carrying the parallel import path.