8000 build(license): Apache-2.0 compliance - no GPL/LGPL code in the connector JARs, THIRD_PARTY_NOTICES.md and license texts by minguyen9988 · Pull Request #1560 · Altinity/clickhouse-sink-connector · GitHub
[go: up one dir, main page]

Skip to content

build(license): Apache-2.0 compliance - no GPL/LGPL code in the connector JARs, THIRD_PARTY_NOTICES.md and license texts - #1560

Merged
minguyen9988 merged 3 commits into
2.11.0from
fix-apache-license-compliance
Oct 10, 2026
Merged

minguyen9988 merged 3 commits into
2.11.0from
fix-apache-license-compliance

Conversation

@minguyen9988
Copy link
Copy Markdown
Collaborator

Summary

Brings the 2.11.0 artifacts in line with the Apache License 2.0, applying the release-packaging requirements of the third-party license review of the 2.10.3 artifacts.

The 2.11.0 lightweight JAR shaded in code that may not be bundled into an Apache-2.0 work (ASF Category X) or that does not belong in a production JAR: MySQL Connector/J 9.1.0 (GPL-2.0 + Universal FOSS Exception, 1,127 entries), MariaDB Connector/J 2.7.12 (LGPL-2.1, 283 entries) and JUnit 4.10 (CPL-1.0, 242 entries, via json-simple). The org.honton.chas license-maven-plugin 0.0.6 compliance goal ran in every build and never failed it.

Java

  • mysql-connector-j is now provided scope: compiled and tested against, not shaded. Debezium MySQL connector links directly against com.mysql.cj.jdbc.Driver, CharsetMapping and protocol.a.NativeConstants, so no other driver can replace it; it is supplied at run time. The JAR manifest has Class-Path: mysql-connector-j.jar lib/mysql-connector-j.jar, so java -jar loads the driver from the directory of the JAR. mvn package copies the unmodified driver and its sources JAR to target/mysql-driver/. The profile bundle-mysql-driver restores the old shading for builds that are never redistributed.
  • New MySqlJdbcDriver.check refuses a MySQL start without the driver and names the three ways to supply it. PostgreSQL pipelines are never affected.
  • ConnectionTimeZonePreflight calls the Connector/J zone resolver by reflection, so no project source links against GPL classes. Behaviour is unchanged.
  • mariadb-java-client moved to test scope (unused in src/main). junit excluded from json-simple. Unused org.glassfish:javax.json removed.
  • maven-enforcer bannedDependencies replaces the no-op plugin. The build fails if Connector/J, the MariaDB driver or JUnit 4 reaches compile or runtime scope.

Python (ch-sink-tools)

  • psycopg2-binary (LGPL-3.0) replaced by pg8000 (BSD-3-Clause; pinned to 1.30 or newer, below 2.0). Rows are still dicts keyed by column name. The 20 s timeout now bounds only the connect, because pg8000 would otherwise keep it on every socket read and cut off long checksum queries. statement_timeout=0 is still sent. The checksum snapshot sets REPEATABLE READ, READ ONLY with SET SESSION CHARACTERISTICS before the implicit BEGIN, and now verifies READ ONLY too.
  • mysql-connector-python (GPL-2.0) replaced by PyMySQL (MIT) in sink-connector/tests and generate_15k_tables.py.

Attribution and packaging

  • New THIRD_PARTY_NOTICES.md covers both JARs, the Go client, the Docker bundles and ch-sink-tools, and keeps the license elections of the review. The Maven table is generated from mvn dependency:tree (runtime scope) on this branch. A section lists what changed since 2.10.3.
  • New licenses/ folder with the GPL-2.0 + Universal FOSS Exception, MPL-2.0, EPL-2.0, CDDL-1.0 and CDDL-1.1 texts.
  • Both JARs carry THIRD_PARTY_NOTICES.md and licenses/ under META-INF/.
  • The lightweight images ship the driver as a separate file next to /app.jar. /licenses/ in the image holds the notices, the license texts and the complete corresponding source of the driver.
  • The release JAR zip includes the notices and licenses/. The notices are also attached as a release asset, which covers the MPL-2.0 dependency of the Go client.
  • The Kafka images no longer download io.confluent:kafka-schema-registry (the registry server, Confluent Community License). The Avro converter depends only on kafka-avro-serializer and kafka-schema-registry-client.
  • sink-connector/deploy/libs/mysql-connector-java-8.0.27.jar (GPL) is removed. The Kafka sink never connects to MySQL.
  • The e2e podman scripts mount the driver next to /app.jar. doc/licensing.md documents the policy, the gate and how to supply the driver.

Operational impact

A MySQL pipeline started from a JAR built from this branch needs mysql-connector-j.jar next to the JAR, or the JAR must be built with the bundle-mysql-driver profile. Without either, it refuses to start with that instruction. Docker images include the driver, so their entrypoints are unchanged. This PR does not touch versioning, de-duplication, watermarking or offset commit timing.

Verification

  • mvn offline clean package for both modules, with tests skipped: BUILD SUCCESS, enforcer rules passed. Neither JAR contains any com/mysql, org/mariadb or junit entries. Both JARs contain META-INF/THIRD_PARTY_NOTICES.md and META-INF/licenses/.
  • Mutation checks:
    • Putting Connector/J in compile scope fails the build (banned).
    • Putting mariadb-java-client in compile scope fails the build (banned).
    • Removing the json-simple junit exclusion fails the build on transitive junit:junit:4.10.
    • The bundle-mysql-driver profile reproduces the old 1,127-entry JAR.
  • JDK 17 checks against the built JAR:
    • With the driver next to the JAR, it loads, also when the JAR is started through a symlink.
    • The reflective resolver returns the same results as the driver (UTC, America/Chicago, +00:00) and rejects CDT with the driver exception.
    • Without the driver, the start is refused.
    • A PostgreSQL connector is skipped.
  • Lightweight unit tests (Test classes): 720 run, 0 failures, 2 errors. Both errors are environmental (no Docker, no raw sockets in the sandbox). The new MySqlJdbcDriverTest passes 6/6 and ConnectionTimeZonePreflightTest passes 10/10.
  • Python unit suite (db_compare, db_dump, db_load, tests): 805 passed before, 810 passed after. The new pg8000 timeout test fails when the fix is removed.
  • Not run: the Testcontainers IT suites, the e2e podman scripts and a live PostgreSQL run of the pg8000 path. The CI e2e workflows cover these.

Whole-Change-Verification: ran=mvn offline clean package of both modules with the enforcer + lightweight unit tests (720 run, 0 failures, 2 environment-only errors) + JAR class-path and refusal checks + pytest db_compare/tests db_dump/tests db_load/tests tests (810 passed); IT, e2e and live-PostgreSQL runs not runnable in the sandbox; result=not-runnable

Opened on behalf of the team that reviewed the 2.10.3 licensing. Maintainers own the review and the merge.

…ctor JARs, THIRD_PARTY_NOTICES.md, license texts

The 2.11.0 lightweight JAR shaded in code under licenses that may not be
bundled into an Apache-2.0 work (ASF Category X) or that do not belong in a
production JAR:
- MySQL Connector/J 9.1.0 (GPL-2.0 + Universal FOSS Exception): 1,127 entries
- MariaDB Connector/J 2.7.12 (LGPL-2.1): 283 entries
- JUnit 4.10 (CPL-1.0, via json-simple's mis-scoped dependency): 242 entries
The org.honton.chas license-maven-plugin 0.0.6 "compliance" goal ran in
every build and never failed it.

Java
- mysql-connector-j is "provided": on the compile/test class path, not
  shaded. Debezium's MySQL connector links directly against
  com.mysql.cj.jdbc.Driver, com.mysql.cj.CharsetMapping and
  com.mysql.cj.protocol.a.NativeConstants, so no other driver can replace
  it; it is supplied at run time instead. The JAR manifest carries
  Class-Path: mysql-connector-j.jar lib/mysql-connector-j.jar, and
  mvn package copies the unmodified driver and its sources JAR to
  target/mysql-driver/. -Pbundle-mysql-driver restores the old shading for
  builds that are never redistributed.
- MySqlJdbcDriver.check refuses a MySQL start without the driver and names
  the three ways to supply it; PostgreSQL is never affected.
- ConnectionTimeZonePreflight calls Connector/J's own zone resolver by
  reflection: no project source links against GPL classes.
- mariadb-java-client -> test scope (unused by src/main); junit excluded
  from json-simple; unused org.glassfish:javax.json removed.
- maven-enforcer bannedDependencies replaces the no-op plugin: the build
  fails if Connector/J, the MariaDB driver or JUnit 4 reaches
  compile/runtime scope.

Python (ch-sink-tools)
- psycopg2-binary (LGPL-3.0) -> pg8000 (BSD-3-Clause, pinned >=1.30,<2).
  Dict rows from cursor.descri
8000
ption; explicit cursor close; the 20 s
  timeout bounds only the connect (pg8000 would keep it on every socket
  read, so it is cleared after connecting); statement_timeout=0 still sent;
  the checksum snapshot uses SET SESSION CHARACTERISTICS ... REPEATABLE
  READ, READ ONLY before the implicit BEGIN and now verifies READ ONLY too.
- mysql-connector-python (GPL-2.0) -> PyMySQL (MIT) in sink-connector/tests
  and generate_15k_tables.py.

Attribution and packaging (per the 2.10.3 third-party license review)
- THIRD_PARTY_NOTICES.md for both JARs, the Go client, the Docker bundles
  and ch-sink-tools, keeping the review's license elections. The Maven
  table is generated from mvn dependency:tree -Dscope=runtime.
- licenses/: GPL-2.0 + UFE, MPL-2.0, EPL-2.0, CDDL-1.0, CDDL-1.1 texts.
- Both JARs carry THIRD_PARTY_NOTICES.md and licenses/ under META-INF/.
- Lightweight images ship the driver as a separate file next to /app.jar,
  plus /licenses/ with the notices, the license texts and the driver's
  complete corresponding source.
- The release JAR zip includes the notices and licenses/; the notices are
  also attached as a release asset.
- Kafka images no longer download io.confluent:kafka-schema-registry (the
  registry server, Confluent Community License): the Avro converter needs
  only kafka-avro-serializer and kafka-schema-registry-client.
- sink-connector/deploy/libs/mysql-connector-java-8.0.27.jar (GPL) removed:
  the Kafka sink never connects to MySQL.
- e2e podman scripts mount the driver next to /app.jar; doc/licensing.md
  documents the policy, the gate and how to supply the driver.

Checks: publish.yml parses with a duplicate-key-detecting YAML loader; the
edited shell scripts pass bash -n; postgres_dumper.py passes the Python unit
suite (810 passed); README text only.

Jinja-Render-Check: rendered=6; formats=yaml,shell,text; result=pass
…pin pg8000 to the verified 1.31 line

Spec-first gate: the license change touched spec-governed sources
(MySqlJdbcDriver, DebeziumChangeEventCapture, ConnectionTimeZonePreflight)
without a spec update.

- Spec 01.01: new section 3.2.1 (the driver is provided-scope, supplied at
  run time via the manifest Class-Path; MySqlJdbcDriver.check runs first
  and refuses a MySQL start without it; non-MySQL connectors untouched),
  Codebase Mapping entry, start-sequence step, FM-01.01-2 trigger and test,
  and the MySqlJdbcDriverTest verification citations.
- Spec 07.03: the session-zone preflight resolves with the driver's own
  TimeUtil.getCanonicalTimeZone, now invoked by reflection through
  MySqlJdbcDriver.canonicalTimeZone.
- pg8000 pinned to >=1.31,<1.32: the connect-timeout fix reads pg8000's
  private _usock, verified on 1.31.5; it still fails loudly (with a test)
  if the attribute is ever missing.
…TESTYLE, PGGEQO, PGSSLMODE)

python-toolset-e2e-postgres failed on
test_zone_less_timestamp_keeps_its_wall_clock_in_a_non_utc_zone (D-13.05-8):
the dumper detected the server zone as UTC instead of America/Chicago and
created DateTime64(6, 'UTC'). Root cause: psycopg2 is libpq-based and libpq
sends PGTZ (and PGDATESTYLE, PGGEQO) from the environment as session
parameters; pg8000 is pure Python and reads none of them, so the session
kept the server default.

get_postgres_connection now passes those variables as pg8000 startup
parameters (TimeZone, DateStyle, geqo) and maps PGSSLMODE to pg8000's
ssl_context (prefer/allow -> None, which is pg8000's TLS-if-offered default
and equals libpq's default; disable -> False; require -> True; verify-ca /
verify-full -> a verifying context using PGSSLROOTCERT). PGCLIENTENCODING is
not mapped: pg8000 decodes UTF-8 only.

Verified:
- the PostgreSQL e2e suite against a real PostgreSQL 16 + ClickHouse 24.8
  (external-stack mode): before the fix 1 failed, 30 passed, 2 xfailed
  (the failure above); after it 31 passed, 2 xfailed.
- python unit suite (db_compare, db_dump, db_load, tests): 818 passed.
- new unit tests for the environment and PGSSLMODE mapping.
@minguyen9988
Copy link
Copy Markdown
Collaborator Author

CI is fully green on 5487049 (15 of 15 checks). This covers the parts the PR description listed as not runnable locally:

  • python-toolset-e2e-postgres passes. Commit 5487049 fixed its first failure: pg8000 does not read the libpq environment, so PGTZ/PGDATESTYLE/PGGEQO/PGSSLMODE are now mapped explicitly.
  • java-tests-lightweight passes (1h53m), with the MySQL driver in provided scope.
  • All 4 testflows-lightweight jobs pass (2h10m to 2h31m). They run against the image that ships the driver as a separate file next to /app.jar.
  • Spec validator, both builds and images, java-tests-kafka, checksum-tests-lightweight, python-toolset-e2e-mysql and python-toolset-unit all pass.

Whole-Change-Verification: ran=full CI pipeline on 5487049 (15 checks); result=pass

@minguyen9988
minguyen9988 merged commit 7f3102d into 2.11.0 Oct 10, 2026
15 checks passed
minguyen9988 added a commit that referenced this pull request Oct 10, 2026
…1560)

This branch and #1560 both add THIRD_PARTY_NOTICES.md, so the PR cannot merge into 2.11.0 (add/add conflict). Take the 2.11.0 version as the base of this PR; the next commit adds the one runtime component this branch listed that the 2.11.0 notice lacks.
minguyen9988 added a commit that referenced this pull request Oct 10, 2026
com.google.protobuf:protobuf-java:3.19.6 (BSD-3-Clause) is a compile-scope dependency of io.debezium:debezium-connector-postgres 3.1.3.Final. sink-connector-lightweight/pom.xml neither excludes it nor filters it out of the shaded JAR, so it ships in the lightweight connector JAR. The 2.10.3 notice in #1561 lists it; the notice regenerated for 2.11.0 in #1560 does not.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
minguyen9988 added a commit that referenced this pull request Oct 10, 2026
* Add THIRD_PARTY_NOTICES.md

* THIRD_PARTY_NOTICES.md: align with the notice regenerated for 2.11.0 (#1560)

This branch and #1560 both add THIRD_PARTY_NOTICES.md, so the PR cannot merge into 2.11.0 (add/add conflict). Take the 2.11.0 version as the base of this PR; the next commit adds the one runtime component this branch listed that the 2.11.0 notice lacks.

* THIRD_PARTY_NOTICES.md: align with 2.11.0 again after #1564

#1564 added the protobuf-java row to the 2.11.0 notice, which re-created the add/add conflict with this branch. The file here is now identical to the 2.11.0 version, so the PR merges cleanly.

* ci: re-run checks after #1568

The Review gates job failed on this branch because the workflow ran the check script from the PR head, which predates it; #1568 makes it use the base branch copy. No content change.

* ci: re-run checks after #1569

Lean proofs and spec validator failed here because the job checked out this branch's head, which predates formal_specs/; #1569 makes it validate the merge commit with 2.11.0. No content change.

---------

Co-authored-by: minguyen9988 <136291932+minguyen9988@users.noreply.github.com>
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.

1 participant

0