Product/security integrity gap
Protected develop@622e5e6c3d534f230c390f10e3832efadfc01825 stores CDC source and target registrations in ID-keyed LinkedHashMaps and currently implements both CdcSourceRegistry.register(...) and CdcTargetRegistry.register(...) as unconditional byId.put(connector.id(), connector).
For sources, Spring beans are discovered with ObjectProvider<CdcSourceConnector>.orderedStream() and registered in sequence. A duplicate connector ID therefore silently lets the later bean replace the earlier implementation. For targets, public in-process registration can likewise replace an existing target. The configured connector ID is an authority selector; silently changing which implementation owns that ID makes startup order or accidental duplicate beans decide execution semantics.
Status: known_gap; bounded fail-closed repair is source-local and does not require credentials, external services, or cross-repository writes.
RCA
- Immediate cause: duplicate IDs use ordinary map replacement semantics.
- Technical root cause: connector identity uniqueness is treated as a map implementation detail instead of a validated registry invariant.
- Systemic/control cause: current registry tests verify presence/discovery but do not prove duplicate registration fails closed.
- Risk: a duplicate/misconfigured connector can shadow a trusted implementation, make
find(id) depend on registration order, and cause status/discovery to describe a different implementation than operators expected.
Smallest remediation
Make duplicate registration a deterministic startup/configuration error:
- reject null connector or blank connector ID;
- use an explicit duplicate-ID check /
putIfAbsent and throw a stable IllegalArgumentException (or a narrower reviewed configuration exception) naming only the non-secret connector ID;
- preserve successful unique registration order and fallback behavior;
- do not silently choose first/last, add priority semantics, or mutate IDs to make duplicates coexist.
A future plugin-priority model, if ever needed, requires an explicit ADR and must not be smuggled in as map ordering.
TDD / acceptance
RED first against the actual registries. Final acceptance must prove:
- two source connectors with the same ID fail deterministically rather than replacing one another;
- registering a target with an existing ID fails deterministically;
- unique registrations remain discoverable in stable insertion order;
- an empty Spring/test source registry still installs the intended PostgreSQL fallback exactly once;
- blank/null connector identities fail before map mutation;
- error text contains no connector config, credentials, payloads or exception-chain diagnostics;
- full CDC tests and current dependency/SBOM/SAST/security evidence remain intact;
- accepted source-identity and non-vacuous coverage controls are satisfied before protected integration.
Writer / scope boundary
Keep this slice limited to CDC registry identity semantics plus focused tests. Do not combine MySQL/SQL Server discovery retirement (#158/#163), generic target-SPI redesign, connector credentials, or the broader target-scaffold lifecycle (#153).
Product/security integrity gap
Protected
develop@622e5e6c3d534f230c390f10e3832efadfc01825stores CDC source and target registrations in ID-keyedLinkedHashMaps and currently implements bothCdcSourceRegistry.register(...)andCdcTargetRegistry.register(...)as unconditionalbyId.put(connector.id(), connector).For sources, Spring beans are discovered with
ObjectProvider<CdcSourceConnector>.orderedStream()and registered in sequence. A duplicate connector ID therefore silently lets the later bean replace the earlier implementation. For targets, public in-process registration can likewise replace an existing target. The configured connector ID is an authority selector; silently changing which implementation owns that ID makes startup order or accidental duplicate beans decide execution semantics.Status:
known_gap; bounded fail-closed repair is source-local and does not require credentials, external services, or cross-repository writes.RCA
find(id)depend on registration order, and cause status/discovery to describe a different implementation than operators expected.Smallest remediation
Make duplicate registration a deterministic startup/configuration error:
putIfAbsentand throw a stableIllegalArgumentException(or a narrower reviewed configuration exception) naming only the non-secret connector ID;A future plugin-priority model, if ever needed, requires an explicit ADR and must not be smuggled in as map ordering.
TDD / acceptance
RED first against the actual registries. Final acceptance must prove:
Writer / scope boundary
Keep this slice limited to CDC registry identity semantics plus focused tests. Do not combine MySQL/SQL Server discovery retirement (#158/#163), generic target-SPI redesign, connector credentials, or the broader target-scaffold lifecycle (#153).