This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-mosaic.git


The following commit(s) were added to refs/heads/main by this push:
     new 12c5a43  fix(release): package complete native license files (#97)
12c5a43 is described below

commit 12c5a436f0eef0a5761eee189904e2dd2ef92690
Author: jianguotian <[email protected]>
AuthorDate: Thu Sep 24 16:37:16 2026 +0800

    fix(release): package complete native license files (#97)
---
 .gitattributes                               |   2 +-
 .github/workflows/ci.yml                     |   5 +-
 .github/workflows/release-java.yml           |  20 +-
 .github/workflows/release-python-publish.yml |   5 +
 .github/workflows/release-python.yml         |  19 ++
 LICENSE-binary                               | 426 +++++++++++++++++++++++++++
 LICENSE-binary-ffi                           | 374 +++++++++++++++++++++++
 java/pom.xml                                 |  37 +++
 python/pyproject.toml                        |  16 +-
 python/setup.py                              |  60 +++-
 python/tests/test_packaging.py               |  81 +++++
 tools/check_license_headers.py               |   2 +
 tools/deploy_java_staging.sh                 |   6 +-
 tools/tests/deploy_java_staging_test.sh      |  14 +
 tools/tests/test_release_vote_workflow.py    |  20 ++
 tools/verify_binary_artifact.py              | 281 ++++++++++++++++++
 16 files changed, 1343 insertions(+), 25 deletions(-)

diff --git a/.gitattributes b/.gitattributes
index 95a71ce..10b43bb 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17,5 +17,5 @@
 # operating systems are collected by the publish job.
 *.html text eol=lf
 *.txt text eol=lf
-LICENSE text eol=lf
+LICENSE* text eol=lf
 NOTICE text eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9bbab44..8b7c691 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -51,6 +51,9 @@ jobs:
       - name: Check dependency licenses (Apache-compatible)
         run: cargo deny check licenses
 
+      - name: Check binary legal inventory
+        run: python3 tools/verify_binary_artifact.py --source
+
       - name: Format
         run: cargo fmt --all -- --check
 
@@ -185,7 +188,7 @@ jobs:
 
       - name: Install Python dependencies
         working-directory: python
-        run: pip install pyarrow pytest
+        run: pip install pyarrow pytest build "setuptools>=77" wheel
 
       - name: Run Python tests
         working-directory: python
diff --git a/.github/workflows/release-java.yml 
b/.github/workflows/release-java.yml
index b3d2a7f..ffd4573 100644
--- a/.github/workflows/release-java.yml
+++ b/.github/workflows/release-java.yml
@@ -188,24 +188,20 @@ jobs:
             test -s "$artifact"
           done
 
-          if jar tf "$sources_jar" | grep -Eq '^native/'; then
-            echo "Sources JAR contains native resources" >&2
-            exit 1
-          fi
+          python3 tools/verify_binary_artifact.py --jar "$jar_file"
 
           for entry in \
-            org/apache/paimon/mosaic/NativeLib.class \
-            native/linux/x86_64/libpaimon_mosaic_jni.so \
-            native/linux/aarch64/libpaimon_mosaic_jni.so \
-            native/macos/aarch64/libpaimon_mosaic_jni.dylib \
-            native/windows/x86_64/paimon_mosaic_jni.dll \
-            META-INF/LICENSE \
-            META-INF/NOTICE \
-            META-INF/DEPENDENCIES
+            META-INF/DEPENDENCIES \
+            org/apache/paimon/mosaic/NativeLib.class
           do
             jar tf "$jar_file" | grep -qx "$entry"
           done
 
+          if jar tf "$sources_jar" | grep -Eq 
'^(native/|META-INF/LICENSE-binary$)'; then
+            echo "Sources JAR contains binary-only resources" >&2
+            exit 1
+          fi
+
           java -cp "$jar_file:java/target/test-classes" \
             org.apache.paimon.mosaic.MosaicNativeLoaderSmokeTest
 
diff --git a/.github/workflows/release-python-publish.yml 
b/.github/workflows/release-python-publish.yml
index 2dcc5c3..cd23062 100644
--- a/.github/workflows/release-python-publish.yml
+++ b/.github/workflows/release-python-publish.yml
@@ -41,12 +41,17 @@ jobs:
     needs: [release-preflight]
     runs-on: ubuntu-latest
     steps:
+      - uses: actions/checkout@v6
+
       - uses: actions/download-artifact@v5
         with:
           pattern: wheels-*
           merge-multiple: true
           path: dist
 
+      - name: Verify wheel legal and native contents
+        run: python3 tools/verify_binary_artifact.py --wheel "dist/*.whl"
+
       - name: Verify wheel versions
         env:
           TAG_NAME: ${{ github.ref_name }}
diff --git a/.github/workflows/release-python.yml 
b/.github/workflows/release-python.yml
index 0497f2c..7f4b377 100644
--- a/.github/workflows/release-python.yml
+++ b/.github/workflows/release-python.yml
@@ -75,6 +75,12 @@ jobs:
             cargo build --release -p paimon-mosaic-ffi &&
             cp target/release/libpaimon_mosaic_ffi.so {package}/mosaic/
 
+      - name: Verify and load wheel
+        run: |
+          python3 tools/verify_binary_artifact.py --wheel "wheelhouse/*.whl"
+          python -m pip install --force-reinstall wheelhouse/*.whl
+          python -c "import mosaic; print(mosaic.__file__)"
+
       - name: Upload wheels
         uses: actions/upload-artifact@v5
         with:
@@ -133,6 +139,12 @@ jobs:
           rm python/dist/*.whl
           mv python/dist/repaired/*.whl python/dist/
 
+      - name: Verify and load wheel
+        run: |
+          python3 tools/verify_binary_artifact.py --wheel "python/dist/*.whl"
+          python -m pip install --force-reinstall python/dist/*.whl
+          python -c "import mosaic; print(mosaic.__file__)"
+
       - name: Upload wheel
         uses: actions/upload-artifact@v5
         with:
@@ -176,6 +188,13 @@ jobs:
         working-directory: python
         run: python -m build --wheel
 
+      - name: Verify and load wheel
+        shell: bash
+        run: |
+          python tools/verify_binary_artifact.py --wheel "python/dist/*.whl"
+          python -m pip install --force-reinstall python/dist/*.whl
+          python -c "import mosaic; print(mosaic.__file__)"
+
       - name: Upload wheel
         uses: actions/upload-artifact@v5
         with:
diff --git a/LICENSE-binary b/LICENSE-binary
new file mode 100644
index 0000000..6901fa5
--- /dev/null
+++ b/LICENSE-binary
@@ -0,0 +1,426 @@
+Apache Paimon Mosaic Java binary distributions
+===============================================
+
+The Java JAR includes the compiled paimon-mosaic-jni Rust dependency closure
+and the Rust standard library.
+
+Except for the components listed below, Apache Paimon Mosaic selects the
+Apache License, Version 2.0 option for dependencies that offer it. The full
+Apache License, Version 2.0 text is in LICENSE.
+
+arrow-array 58.4.0
+------------------
+
+This component is distributed under both the Apache License, Version 2.0 and
+the following MIT license.
+
+MIT License
+
+Copyright (c) 2020-2022 Oliver Margetts
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+bytes 1.12.1
+------------
+
+Copyright (c) 2018 Carl Lerche
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+combine 4.6.7
+-------------
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Markus Westerlind
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+crunchy 0.2.4
+-------------
+
+The MIT License (MIT)
+
+Copyright 2017-2023 Eira Fransham.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+libm 0.2.16
+-----------
+
+This component is distributed under the following MIT license option.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+This Rust library contains the following copyrights:
+
+    Copyright (c) 2018 Jorge Aparicio
+
+Portions of this software are derived from third-party works licensed under
+terms compatible with the above MIT license:
+
+* musl libc https://www.musl-libc.org/. This library contains the following
+  copyright:
+
+      Copyright © 2005-2020 Rich Felker, et al.
+
+* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH
+  routines are available under the MIT license on a per-file basis.
+
+The musl libc COPYRIGHT file also includes the following notice relevant to
+math portions of the library:
+
+Much of the math library code (src/math/* and src/complex/*) is
+Copyright © 1993,2004 Sun Microsystems or
+Copyright © 2003-2011 David Schultz or
+Copyright © 2003-2009 Steven G. Kargl or
+Copyright © 2003-2009 Bruce D. Evans or
+Copyright © 2008 Stephen L. Moshier or
+Copyright © 2017-2018 Arm Limited
+and labelled as such in comments in the individual source files. All
+have been licensed under extremely permissive terms.
+
+Copyright notices are retained in src/* files where relevant.
+
+memchr 2.8.3
+------------
+
+This component is distributed under the following MIT license option.
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Andrew Gallant
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+tiny-keccak 2.0.2
+-----------------
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+unicode-ident 1.0.24 and Rust standard library 1.97.1
+---------------------------------------------------
+
+The Rust code is distributed under the Apache License, Version 2.0 option.
+Unicode data from unicode-ident has Copyright © 1991-2023 Unicode, Inc.
+Unicode data from the Rust standard library has
+Copyright © 1991-2024 Unicode, Inc. Both are additionally covered by the
+following Unicode License V3.
+
+UNICODE LICENSE V3
+
+COPYRIGHT AND PERMISSION NOTICE
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
+SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
+DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of data files and any associated documentation (the "Data Files") or
+software and any associated documentation (the "Software") to deal in the
+Data Files or Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that either (a)
+this copyright and permission notice appear with all copies of the Data
+Files or Software, or (b) this copyright and permission notice appear in
+associated Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+THIRD PARTY RIGHTS.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
+BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
+FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
+
+zstd 0.13.3
+-----------
+
+The MIT License (MIT)
+Copyright (c) 2016 Alexandre Bury
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+zstd-sys 2.0.16+zstd.1.5.7 (vendored Zstandard 1.5.7)
+-----------------------------------------------------
+
+BSD License
+
+For Zstandard software
+
+Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook, nor Meta, nor the names of its contributors may
+   be used to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/LICENSE-binary-ffi b/LICENSE-binary-ffi
new file mode 100644
index 0000000..ed0bf61
--- /dev/null
+++ b/LICENSE-binary-ffi
@@ -0,0 +1,374 @@
+Apache Paimon Mosaic Python binary distributions
+================================================
+
+The Python wheels include the compiled paimon-mosaic-ffi Rust dependency
+closure and the Rust standard library.
+
+Except for the components listed below, Apache Paimon Mosaic selects the
+Apache License, Version 2.0 option for dependencies that offer it. The full
+Apache License, Version 2.0 text is in LICENSE.
+
+arrow-array 58.4.0
+------------------
+
+This component is distributed under both the Apache License, Version 2.0 and
+the following MIT license.
+
+MIT License
+
+Copyright (c) 2020-2022 Oliver Margetts
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+bytes 1.12.1
+------------
+
+Copyright (c) 2018 Carl Lerche
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+crunchy 0.2.4
+-------------
+
+The MIT License (MIT)
+
+Copyright 2017-2023 Eira Fransham.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+libm 0.2.16
+-----------
+
+This component is distributed under the following MIT license option.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+This Rust library contains the following copyrights:
+
+    Copyright (c) 2018 Jorge Aparicio
+
+Portions of this software are derived from third-party works licensed under
+terms compatible with the above MIT license:
+
+* musl libc https://www.musl-libc.org/. This library contains the following
+  copyright:
+
+      Copyright © 2005-2020 Rich Felker, et al.
+
+* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH
+  routines are available under the MIT license on a per-file basis.
+
+The musl libc COPYRIGHT file also includes the following notice relevant to
+math portions of the library:
+
+Much of the math library code (src/math/* and src/complex/*) is
+Copyright © 1993,2004 Sun Microsystems or
+Copyright © 2003-2011 David Schultz or
+Copyright © 2003-2009 Steven G. Kargl or
+Copyright © 2003-2009 Bruce D. Evans or
+Copyright © 2008 Stephen L. Moshier or
+Copyright © 2017-2018 Arm Limited
+and labelled as such in comments in the individual source files. All
+have been licensed under extremely permissive terms.
+
+Copyright notices are retained in src/* files where relevant.
+
+tiny-keccak 2.0.2
+-----------------
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+unicode-ident 1.0.24 and Rust standard library 1.97.1
+---------------------------------------------------
+
+The Rust code is distributed under the Apache License, Version 2.0 option.
+Unicode data from unicode-ident has Copyright © 1991-2023 Unicode, Inc.
+Unicode data from the Rust standard library has
+Copyright © 1991-2024 Unicode, Inc. Both are additionally covered by the
+following Unicode License V3.
+
+UNICODE LICENSE V3
+
+COPYRIGHT AND PERMISSION NOTICE
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
+SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
+DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of data files and any associated documentation (the "Data Files") or
+software and any associated documentation (the "Software") to deal in the
+Data Files or Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that either (a)
+this copyright and permission notice appear with all copies of the Data
+Files or Software, or (b) this copyright and permission notice appear in
+associated Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+THIRD PARTY RIGHTS.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
+BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
+FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
+
+zstd 0.13.3
+-----------
+
+The MIT License (MIT)
+Copyright (c) 2016 Alexandre Bury
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+zstd-sys 2.0.16+zstd.1.5.7 (vendored Zstandard 1.5.7)
+-----------------------------------------------------
+
+BSD License
+
+For Zstandard software
+
+Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook, nor Meta, nor the names of its contributors may
+   be used to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/java/pom.xml b/java/pom.xml
index a1259fe..438ac23 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -114,6 +114,41 @@
             <id>release</id>
             <build>
                 <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-resources-plugin</artifactId>
+                        <version>3.3.1</version>
+                        <executions>
+                            <execution>
+                                <id>copy-binary-legal-resources</id>
+                                <phase>prepare-package</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
+                                    <overwrite>true</overwrite>
+                                    <resources>
+                                        <resource>
+                                            
<directory>${project.basedir}/..</directory>
+                                            <targetPath>META-INF</targetPath>
+                                            <filtering>false</filtering>
+                                            <includes>
+                                                
<include>LICENSE-binary</include>
+                                            </includes>
+                                        </resource>
+                                        <resource>
+                                            
<directory>src/main/binary-resources</directory>
+                                            <filtering>false</filtering>
+                                            <includes>
+                                                
<include>META-INF/NOTICE</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-gpg-plugin</artifactId>
@@ -150,6 +185,8 @@
                         <configuration>
                             <excludes>
                                 <exclude>native/**</exclude>
+                                <exclude>LICENSE-binary</exclude>
+                                <exclude>**/LICENSE-binary</exclude>
                             </excludes>
                         </configuration>
                     </plugin>
diff --git a/python/pyproject.toml b/python/pyproject.toml
index 746ee1c..b9b2e72 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -16,22 +16,30 @@
 # under the License.
 
 [build-system]
-requires = ["setuptools>=64"]
+requires = ["setuptools>=77", "wheel"]
 build-backend = "setuptools.build_meta"
 
 [project]
 name = "paimon-mosaic"
 version = "0.3.0"
 description = "Python bindings for the Mosaic columnar-bucket hybrid file 
format"
-license = {text = "Apache-2.0"}
+license = "Apache-2.0"
+license-files = ["LICENSE", "NOTICE", "LICENSE-binary"]
 requires-python = ">=3.9"
 dependencies = ["pyarrow"]
 
 [project.optional-dependencies]
-test = ["pytest"]
+test = ["pytest", "build", "setuptools>=77", "wheel"]
 
 [tool.setuptools.packages.find]
 include = ["mosaic*"]
 
 [tool.setuptools.package-data]
-mosaic = ["libpaimon_mosaic_ffi.dylib", "libpaimon_mosaic_ffi.so", 
"paimon_mosaic_ffi.dll"]
+mosaic = [
+    "LICENSE",
+    "NOTICE",
+    "LICENSE-binary",
+    "libpaimon_mosaic_ffi.dylib",
+    "libpaimon_mosaic_ffi.so",
+    "paimon_mosaic_ffi.dll",
+]
diff --git a/python/setup.py b/python/setup.py
index d1a6569..8180fdf 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-"""Build helper: copies the pre-built native library into the package 
directory."""
+"""Build helper: stages the native library and binary-distribution legal 
files."""
 
 import os
 import platform
@@ -26,6 +26,14 @@ from setuptools.command.build_py import build_py
 from wheel.bdist_wheel import bdist_wheel
 
 
+LEGAL_FILES = ("LICENSE", "NOTICE", "LICENSE-binary")
+LEGAL_SOURCE_FILES = {
+    "LICENSE": "../LICENSE",
+    "NOTICE": "../java/src/main/binary-resources/META-INF/NOTICE",
+    "LICENSE-binary": "../LICENSE-binary-ffi",
+}
+
+
 def _lib_name():
     system = platform.system()
     if system == "Darwin":
@@ -53,6 +61,34 @@ def _find_native_lib():
     return None
 
 
+def _stage_legal_files(destination_dir):
+    here = os.path.dirname(os.path.abspath(__file__))
+    staged = []
+
+    for name in LEGAL_FILES:
+        source = os.path.join(here, LEGAL_SOURCE_FILES[name])
+        destination = os.path.join(destination_dir, name)
+        if not os.path.isfile(source):
+            # An extracted sdist carries these files alongside setup.py.
+            source = os.path.join(here, name)
+        if not os.path.isfile(source):
+            raise RuntimeError(f"required binary legal file is missing: 
{source}")
+        if os.path.exists(destination):
+            with open(source, "rb") as source_file:
+                source_bytes = source_file.read()
+            with open(destination, "rb") as destination_file:
+                destination_bytes = destination_file.read()
+            if source_bytes != destination_bytes:
+                raise RuntimeError(
+                    f"staged binary legal file does not match source: 
{destination}"
+                )
+            continue
+        shutil.copy2(source, destination)
+        staged.append(destination)
+
+    return staged
+
+
 class BuildPyWithNativeLib(build_py):
     def run(self):
         src = _find_native_lib()
@@ -61,7 +97,14 @@ class BuildPyWithNativeLib(build_py):
                 os.path.dirname(os.path.abspath(__file__)), "mosaic", 
_lib_name()
             )
             shutil.copy2(src, dst)
-        super().run()
+        staged_legal_files = _stage_legal_files(
+            os.path.join(os.path.dirname(os.path.abspath(__file__)), "mosaic")
+        )
+        try:
+            super().run()
+        finally:
+            for path in staged_legal_files:
+                os.remove(path)
 
 
 class PlatformWheel(bdist_wheel):
@@ -83,7 +126,14 @@ class BinaryDistribution(Distribution):
         return True
 
 
-setup(
-    cmdclass={"build_py": BuildPyWithNativeLib, "bdist_wheel": PlatformWheel},
-    distclass=BinaryDistribution,
+staged_distribution_legal_files = _stage_legal_files(
+    os.path.dirname(os.path.abspath(__file__))
 )
+try:
+    setup(
+        cmdclass={"build_py": BuildPyWithNativeLib, "bdist_wheel": 
PlatformWheel},
+        distclass=BinaryDistribution,
+    )
+finally:
+    for path in staged_distribution_legal_files:
+        os.remove(path)
diff --git a/python/tests/test_packaging.py b/python/tests/test_packaging.py
new file mode 100644
index 0000000..bd2904f
--- /dev/null
+++ b/python/tests/test_packaging.py
@@ -0,0 +1,81 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import sys
+import tarfile
+
+from mosaic._ffi import lib
+
+
+ROOT = Path(__file__).resolve().parents[2]
+
+
+def test_sdist_to_wheel_preserves_canonical_legal_files(tmp_path):
+    repository = tmp_path / "repository"
+    package = repository / "python"
+    shutil.copytree(
+        ROOT / "python/mosaic",
+        package / "mosaic",
+        ignore=shutil.ignore_patterns("__pycache__"),
+    )
+    for name in ("setup.py", "pyproject.toml"):
+        shutil.copy2(ROOT / "python" / name, package / name)
+    legal_sources = {
+        "LICENSE": "LICENSE",
+        "NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
+        "LICENSE-binary": "LICENSE-binary-ffi",
+    }
+    for source in legal_sources.values():
+        destination = repository / source
+        destination.parent.mkdir(parents=True, exist_ok=True)
+        shutil.copy2(ROOT / source, destination)
+
+    # The default build extracts its sdist outside the repository before
+    # building the wheel, so only the bundled legal files remain available.
+    result = subprocess.run(
+        [sys.executable, "-m", "build", "--no-isolation", str(package)],
+        env={**os.environ, "MOSAIC_LIB_PATH": 
str(Path(lib._name).resolve().parent)},
+        capture_output=True,
+        text=True,
+        timeout=120,
+    )
+    assert result.returncode == 0, result.stdout + result.stderr
+
+    sdist, = (package / "dist").glob("*.tar.gz")
+    with tarfile.open(sdist) as archive:
+        prefix = sdist.name.removesuffix(".tar.gz")
+        for name, source in legal_sources.items():
+            with archive.extractfile(f"{prefix}/{name}") as legal_file:
+                assert legal_file.read() == (ROOT / source).read_bytes()
+
+    wheel, = (package / "dist").glob("*.whl")
+    result = subprocess.run(
+        [
+            sys.executable,
+            str(ROOT / "tools/verify_binary_artifact.py"),
+            "--wheel",
+            str(wheel),
+        ],
+        capture_output=True,
+        text=True,
+        timeout=30,
+    )
+    assert result.returncode == 0, result.stdout + result.stderr
diff --git a/tools/check_license_headers.py b/tools/check_license_headers.py
index 0ac20cc..a9e8c31 100755
--- a/tools/check_license_headers.py
+++ b/tools/check_license_headers.py
@@ -60,6 +60,8 @@ EXEMPT_FILES = {
     "ffi/DEPENDENCIES.rust.tsv",
     "jni/DEPENDENCIES.rust.tsv",
     "LICENSE",
+    "LICENSE-binary",
+    "LICENSE-binary-ffi",
     "NOTICE",
     "core/LICENSE",
     "core/NOTICE",
diff --git a/tools/deploy_java_staging.sh b/tools/deploy_java_staging.sh
index 8b5dee9..f4737d4 100755
--- a/tools/deploy_java_staging.sh
+++ b/tools/deploy_java_staging.sh
@@ -250,7 +250,7 @@ else
 fi
 
 check_java_package_inputs_clean() {
-  local paths=(java tools/deploy_java_staging.sh)
+  local paths=(java LICENSE-binary tools/deploy_java_staging.sh 
tools/verify_binary_artifact.py)
   local untracked
 
   if ! git -C "$REPO_DIR" diff --quiet -- "${paths[@]}" ||
@@ -543,7 +543,7 @@ validate_maven_artifacts() {
   done
 
   for artifact in "$sources_jar" "$ci_sources_jar"; do
-    if grep -Eq '^native/' <<<"$(jar tf "$artifact")"; then
+    if grep -Eq '^(native/|META-INF/LICENSE-binary$)' <<<"$(jar tf 
"$artifact")"; then
       echo "Sources jar contains binary-only resources: $artifact" >&2
       exit 1
     fi
@@ -559,6 +559,7 @@ validate_maven_artifacts() {
       native/windows/x86_64/paimon_mosaic_jni.dll \
       META-INF/LICENSE \
       META-INF/NOTICE \
+      META-INF/LICENSE-binary \
       META-INF/DEPENDENCIES
     do
       if ! jar tf "$main_jar" | grep -qx "$entry"; then
@@ -566,6 +567,7 @@ validate_maven_artifacts() {
         exit 1
       fi
     done
+    python3 "$REPO_DIR/tools/verify_binary_artifact.py" --jar "$main_jar"
   done
 
   local test_classes="$REPO_DIR/java/target/test-classes"
diff --git a/tools/tests/deploy_java_staging_test.sh 
b/tools/tests/deploy_java_staging_test.sh
index ee6922b..9e08c2b 100755
--- a/tools/tests/deploy_java_staging_test.sh
+++ b/tools/tests/deploy_java_staging_test.sh
@@ -22,6 +22,7 @@ set -o nounset
 set -o pipefail
 
 SOURCE_REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
+REAL_PYTHON=$(command -v python3)
 TEST_ROOT=$(mktemp -d)
 trap 'rm -rf "$TEST_ROOT"' EXIT
 TESTS=0
@@ -131,11 +132,21 @@ native/macos/aarch64/libpaimon_mosaic_jni.dylib
 native/windows/x86_64/paimon_mosaic_jni.dll
 META-INF/LICENSE
 META-INF/NOTICE
+META-INF/LICENSE-binary
 META-INF/DEPENDENCIES
 ENTRIES
 if [[ "${OMIT_NATIVE_ENTRY:-0}" == 1 ]]; then
   exit 0
 fi
+MOCK
+  cat > "$MOCK_BIN/python3" <<'MOCK'
+#!/usr/bin/env bash
+set -euo pipefail
+if [[ "${1-}" == */tools/verify_binary_artifact.py ]]; then
+  printf 'python3 %s\n' "$*" >> "$MOCK_LOG"
+  exit 0
+fi
+exec "$REAL_PYTHON" "$@"
 MOCK
   # Rewrite the mock when an entry must be omitted; doing it here keeps the
   # normal listing easy to audit.
@@ -184,6 +195,7 @@ run_stage() {
     MOCK_LOG="$MOCK_LOG" \
     MOCK_RUN_SHA="${MOCK_RUN_SHA:-$HEAD_SHA}" \
     MOCK_TAG=v1.2.3-rc1 \
+    REAL_PYTHON="$REAL_PYTHON" \
     OMIT_CI_JAVADOC="${OMIT_CI_JAVADOC:-0}" \
     OMIT_LOCAL_MAIN="${OMIT_LOCAL_MAIN:-0}" \
     "$FIXTURE/tools/deploy_java_staging.sh" \
@@ -207,6 +219,8 @@ done
 assert_contains "$MOCK_LOG" "mvn clean verify -Prelease -Dgpg.skip=true 
-DskipTests"
 assert_not_contains "$MOCK_LOG" "mvn deploy"
 [[ $(grep -c '^java ' "$MOCK_LOG") -eq 2 ]] || fail "dry-run must smoke local 
and CI JARs"
+[[ $(grep -c '^python3 .*verify_binary_artifact.py' "$MOCK_LOG") -eq 2 ]] ||
+  fail "dry-run must verify local and CI JAR contents"
 pass "successful dry-run validates all five artifacts and both JARs"
 
 new_fixture
diff --git a/tools/tests/test_release_vote_workflow.py 
b/tools/tests/test_release_vote_workflow.py
index ab83434..091393b 100644
--- a/tools/tests/test_release_vote_workflow.py
+++ b/tools/tests/test_release_vote_workflow.py
@@ -19,6 +19,7 @@ from __future__ import annotations
 
 import copy
 from pathlib import Path
+import subprocess
 
 import pytest
 import yaml
@@ -155,6 +156,25 @@ git diff --check "$(git merge-base HEAD 
"${comparison_ref}")" HEAD
 """
 
 
+def test_binary_licenses_keep_canonical_bytes_with_autocrlf(tmp_path: Path) -> 
None:
+    names = ("LICENSE-binary", "LICENSE-binary-ffi")
+    subprocess.run(["git", "init", "--quiet", str(tmp_path)], check=True)
+    for name in (".gitattributes", *names):
+        (tmp_path / name).write_bytes((ROOT / name).read_bytes())
+    subprocess.run(
+        ["git", "add", "--", ".gitattributes", *names], cwd=tmp_path, 
check=True
+    )
+    for name in names:
+        (tmp_path / name).unlink()
+    subprocess.run(
+        ["git", "-c", "core.autocrlf=true", "checkout-index", "--", *names],
+        cwd=tmp_path,
+        check=True,
+    )
+    for name in names:
+        assert (tmp_path / name).read_bytes() == (ROOT / name).read_bytes(), 
name
+
+
 def load_workflow(path: Path) -> dict:
     return yaml.load(path.read_text(encoding="utf-8"), Loader=yaml.BaseLoader)
 
diff --git a/tools/verify_binary_artifact.py b/tools/verify_binary_artifact.py
new file mode 100644
index 0000000..e3685a9
--- /dev/null
+++ b/tools/verify_binary_artifact.py
@@ -0,0 +1,281 @@
+#!/usr/bin/env python3
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Verify legal files and native resources in binary convenience artifacts."""
+
+import argparse
+import glob
+import json
+import subprocess
+import sys
+import zipfile
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parent.parent
+LEGAL_FILES = ("LICENSE", "NOTICE", "LICENSE-binary")
+WHEEL_LEGAL_SOURCES = {
+    "LICENSE": "LICENSE",
+    "NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
+    "LICENSE-binary": "LICENSE-binary-ffi",
+}
+JAR_LEGAL_SOURCES = {
+    "NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
+    "LICENSE-binary": "LICENSE-binary",
+}
+JAR_NATIVE_FILES = (
+    "native/linux/x86_64/libpaimon_mosaic_jni.so",
+    "native/linux/aarch64/libpaimon_mosaic_jni.so",
+    "native/macos/aarch64/libpaimon_mosaic_jni.dylib",
+    "native/windows/x86_64/paimon_mosaic_jni.dll",
+)
+SUPPORTED_TARGETS = (
+    "x86_64-unknown-linux-gnu",
+    "aarch64-unknown-linux-gnu",
+    "aarch64-apple-darwin",
+    "x86_64-pc-windows-msvc",
+)
+
+
+def resolve_artifacts(patterns):
+    artifacts = []
+    for pattern in patterns:
+        matches = sorted(glob.glob(pattern))
+        if not matches:
+            raise ValueError(f"artifact pattern matched no files: {pattern}")
+        artifacts.extend(Path(match) for match in matches)
+    return artifacts
+
+
+def require_entries(archive, artifact, entries):
+    names = set(archive.namelist())
+    missing = [entry for entry in entries if entry not in names]
+    if missing:
+        raise ValueError(f"{artifact} is missing entries: {', 
'.join(missing)}")
+
+
+def require_canonical_content(archive, artifact, archive_prefix, sources):
+    for name, source in sources.items():
+        entry = f"{archive_prefix}/{name}"
+        expected = (ROOT / source).read_bytes()
+        actual = archive.read(entry)
+        if actual != expected:
+            raise ValueError(f"{artifact}!/{entry} does not match repository 
{source}")
+
+
+def verify_wheel(artifact):
+    with zipfile.ZipFile(artifact) as archive:
+        names = archive.namelist()
+        metadata = [name for name in names if 
name.endswith(".dist-info/METADATA")]
+        if len(metadata) != 1:
+            raise ValueError(
+                f"{artifact} must contain exactly one .dist-info/METADATA 
entry"
+            )
+        dist_info = metadata[0][: -len("METADATA")]
+        dist_legal = [f"{dist_info}licenses/{name}" for name in LEGAL_FILES]
+        package_legal = [f"mosaic/{name}" for name in LEGAL_FILES]
+        require_entries(archive, artifact, dist_legal + package_legal)
+        require_canonical_content(
+            archive, artifact, "mosaic", WHEEL_LEGAL_SOURCES
+        )
+        require_canonical_content(
+            archive,
+            artifact,
+            f"{dist_info}licenses".rstrip("/"),
+            WHEEL_LEGAL_SOURCES,
+        )
+
+        native_names = [
+            name
+            for name in names
+            if name.startswith("mosaic/")
+            and name.endswith((".so", ".dylib", ".dll"))
+        ]
+        if len(native_names) != 1:
+            raise ValueError(
+                f"{artifact} must contain exactly one platform native library, 
found "
+                f"{len(native_names)}"
+            )
+
+    print(f"Verified Python wheel: {artifact}")
+
+
+def verify_jar(artifact, native_files):
+    with zipfile.ZipFile(artifact) as archive:
+        required = (
+            "META-INF/LICENSE",
+            "META-INF/NOTICE",
+            "META-INF/LICENSE-binary",
+            "META-INF/DEPENDENCIES",
+            "org/apache/paimon/mosaic/NativeLib.class",
+        ) + tuple(native_files)
+        require_entries(archive, artifact, required)
+        require_canonical_content(
+            archive,
+            artifact,
+            "META-INF",
+            JAR_LEGAL_SOURCES,
+        )
+
+    print(f"Verified Java JAR: {artifact}")
+
+
+def cargo_metadata(target):
+    return json.loads(
+        subprocess.check_output(
+            [
+                "cargo",
+                "metadata",
+                "--format-version",
+                "1",
+                "--locked",
+                "--filter-platform",
+                target,
+            ],
+            cwd=ROOT,
+            text=True,
+        )
+    )
+
+
+def resolved_runtime_dependencies(metadata, root_name):
+    packages = {package["id"]: package for package in metadata["packages"]}
+    nodes = {node["id"]: node for node in metadata["resolve"]["nodes"]}
+    roots = [
+        package["id"]
+        for package in metadata["packages"]
+        if package["source"] is None and package["name"] == root_name
+    ]
+    if len(roots) != 1:
+        raise ValueError(f"expected one workspace package named {root_name}")
+
+    resolved = set()
+    pending = roots
+    while pending:
+        package_id = pending.pop()
+        if package_id in resolved:
+            continue
+        resolved.add(package_id)
+        for dependency in nodes[package_id]["deps"]:
+            if any(
+                kind["kind"] in (None, "normal")
+                for kind in dependency["dep_kinds"]
+            ):
+                pending.append(dependency["pkg"])
+
+    return [
+        packages[package_id]
+        for package_id in resolved
+        if packages[package_id]["source"] is not None
+    ]
+
+
+def verify_source_legal_inventory():
+    metadata_by_target = [cargo_metadata(target) for target in 
SUPPORTED_TARGETS]
+    for root_name, license_name in (
+        ("paimon-mosaic-ffi", "LICENSE-binary-ffi"),
+        ("paimon-mosaic-jni", "LICENSE-binary"),
+    ):
+        dependencies = {}
+        for metadata in metadata_by_target:
+            for package in resolved_runtime_dependencies(metadata, root_name):
+                marker = f"{package['name']} {package['version']}"
+                dependencies[marker] = package.get("license") or ""
+
+        binary_license = (ROOT / license_name).read_text(encoding="utf-8")
+        missing = []
+        for marker, expression in sorted(dependencies.items()):
+            needs_additional_text = (
+                "Apache-2.0" not in expression or " AND " in expression
+            )
+            if needs_additional_text and marker not in binary_license:
+                missing.append(f"{marker} ({expression})")
+
+        for marker in (
+            "Rust standard library 1.97.1",
+            "zstd-sys 2.0.16+zstd.1.5.7",
+        ):
+            if marker not in binary_license:
+                missing.append(marker)
+
+        if missing:
+            raise ValueError(
+                f"{license_name} does not account for {root_name} runtime "
+                f"dependencies: {', '.join(missing)}"
+            )
+
+    for name in (
+        "LICENSE",
+        "NOTICE",
+        "LICENSE-binary",
+        "LICENSE-binary-ffi",
+        "ffi/DEPENDENCIES.rust.tsv",
+        "jni/DEPENDENCIES.rust.tsv",
+        "java/src/main/binary-resources/META-INF/NOTICE",
+    ):
+        if not (ROOT / name).is_file():
+            raise ValueError(f"repository legal file is missing: {name}")
+
+    print("Verified binary legal inventory against native Rust dependencies")
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("--wheel", nargs="+", default=[], help="Wheel path or 
glob")
+    parser.add_argument("--jar", nargs="+", default=[], help="JAR path or 
glob")
+    parser.add_argument(
+        "--jar-native",
+        action="append",
+        choices=JAR_NATIVE_FILES,
+        help=(
+            "Native entry required in a JAR. Repeat for a partial-platform CI 
build; "
+            "the default requires every release platform."
+        ),
+    )
+    parser.add_argument(
+        "--source",
+        action="store_true",
+        help="Verify LICENSE-binary against native Rust runtime dependencies",
+    )
+    args = parser.parse_args()
+
+    if not args.wheel and not args.jar and not args.source:
+        parser.error("at least one --source, --wheel, or --jar is required")
+
+    try:
+        if args.source:
+            verify_source_legal_inventory()
+        for artifact in resolve_artifacts(args.wheel):
+            verify_wheel(artifact)
+        for artifact in resolve_artifacts(args.jar):
+            verify_jar(artifact, args.jar_native or JAR_NATIVE_FILES)
+    except (
+        KeyError,
+        OSError,
+        subprocess.CalledProcessError,
+        ValueError,
+        zipfile.BadZipFile,
+    ) as error:
+        print(f"Binary artifact verification failed: {error}", file=sys.stderr)
+        return 1
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main())

Reply via email to