Skip to content

[Connector integrity] Reject duplicate CDC connector IDs instead of silently replacing registrations #200

Description

@seonghobae

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:

  1. two source connectors with the same ID fail deterministically rather than replacing one another;
  2. registering a target with an existing ID fails deterministically;
  3. unique registrations remain discoverable in stable insertion order;
  4. an empty Spring/test source registry still installs the intended PostgreSQL fallback exactly once;
  5. blank/null connector identities fail before map mutation;
  6. error text contains no connector config, credentials, payloads or exception-chain diagnostics;
  7. full CDC tests and current dependency/SBOM/SAST/security evidence remain intact;
  8. 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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: dependenciesDependency or lockfile maintenancearea: securitySecurity boundary, hardening, or vulnerability preventionbugSomething isn't workingpriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions