diff --git a/.gitea/workflows/cpp-tests.yml b/.gitea/workflows/cpp-tests.yml index 8b60d16..af8baf8 100644 --- a/.gitea/workflows/cpp-tests.yml +++ b/.gitea/workflows/cpp-tests.yml @@ -112,3 +112,51 @@ jobs: # the price of guaranteeing the documented workflow stays working. - name: End-to-end smoke test (scripts/try_it.sh) run: bash scripts/try_it.sh + +# ───────────────────────────────────────────────────────────────────────────── +# Job 3 — quality-gates (style + convention block) +# +# Cheap, deterministic checks that should never break unless a contributor +# introduces a regression. Each gate is a script under scripts/quality/ +# and exits 0 only when its tree is clean. These ran for weeks locally +# at zero findings before being promoted here. +# +# Tools installed at job-start (the ci-cpp image already has python3 + +# bash; we add codespell + shellcheck on top). Total wall-time: ~30 s +# on the eulernest runner. +# +# Strictly required for merges into main/dev — a regression fails the PR. +# ───────────────────────────────────────────────────────────────────────────── + quality-gates: + needs: test-fast + runs-on: eulernest + container: + image: git.eulernest.eu/conformallab/ci-cpp:latest + + steps: + - uses: actions/checkout@v4 + + - name: Install codespell + shellcheck (job-local) + run: | + apt-get update -qq + apt-get install -y --no-install-recommends \ + codespell shellcheck + + - name: License headers (every C++ source carries MIT SPDX) + run: bash scripts/quality/license-headers.sh + + - name: CGAL conventions (6 rules over CGAL public headers) + run: python3 scripts/quality/cgal-conventions.py + + - name: codespell (docs + source comments + script messages) + run: bash scripts/quality/codespell.sh + + - name: shellcheck (scripts/**/*.sh, severity=warning, strict) + run: bash scripts/quality/shellcheck.sh --strict + + - name: Summary + if: always() + run: | + echo "QUALITY ▸ all four gates passed." + echo " see scripts/quality/README.md for the full catalogue" + echo " (sanitizers, clang-tidy, coverage, etc. are local-only)" diff --git a/code/.gitignore b/code/.gitignore index 7c0f88c..d7ac37b 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -13,6 +13,7 @@ deps/* !deps/tarballs !deps/single_includes/ !deps/CMakeLists.txt +!deps/THIRD-PARTY-LICENSES.md # macOS iCloud Drive duplicates ("file 2.cpp", "file 2.hpp", …) * 2.* diff --git a/code/deps/THIRD-PARTY-LICENSES.md b/code/deps/THIRD-PARTY-LICENSES.md new file mode 100644 index 0000000..31fc209 --- /dev/null +++ b/code/deps/THIRD-PARTY-LICENSES.md @@ -0,0 +1,98 @@ +# Third-party licenses + +This directory contains source code from external projects that +conformallab++ vendors at fixed versions for build reproducibility. +Each project is governed by its own license; this file enumerates them +so downstream packagers, distributors, and reviewers can audit +compatibility without crawling each upstream tarball. + +> **Why vendored at all?** conformallab++ is header-only and ships +> nothing it does not author except the optional CLI binary +> (`-DWITH_CGAL=ON`). Vendoring guarantees that the CGAL / Eigen / +> Boost API surface every contributor sees is identical, removing +> "works on my machine because I have CGAL 6.0 not 5.6" failure modes +> during early review. Downstream packagers replacing the vendored +> trees with system installs is supported and is the recommended path +> for distribution-level packaging (see `doc/architecture/dependencies.md`). + +## conformallab++ itself + +| Item | License | Notes | +|---|---|---| +| `code/include/**`, `code/src/**`, `code/tests/**`, `scripts/**`, `doc/**` | **MIT** (see `LICENSE` at repo root) | Every C++ source file carries `SPDX-License-Identifier: MIT`; CI gate `scripts/quality/license-headers.sh` enforces this. | + +## Vendored dependencies + +The table below lists each tree under `code/deps/`, its upstream +license, the SPDX identifier, and any compatibility note relevant to +shipping conformallab++ as MIT. + +| Directory | Upstream project | Version | License (SPDX) | Compatibility with MIT distribution | Notes | +|---|---|---|---|---|---| +| `CGAL-6.1.1/` | [CGAL](https://www.cgal.org) | 6.1.1 | **LGPL-3.0-or-later** (most headers) + **GPL-3.0-or-later** (a small subset — see CGAL's per-header `\cgal_license{...}` macro) | Header-only consumption is compatible; we ONLY include LGPL'd parts (`Surface_mesh`, `Polygon_mesh_processing`, BGL adapters, kernels). | conformallab++ does not include any of the GPL-only CGAL packages (e.g. `Triangulation_3` parts, certain mesh-3 internals). The `\cgal_license` macro is checked at compile time and would fail the build if a GPL-only header were transitively pulled in. Commercial licenses are available from GeometryFactory for users who can't accept (L)GPL. | +| `eigen-3.4.0/` | [Eigen](https://eigen.tuxfamily.org) | 3.4.0 | **MPL-2.0** for almost everything, **LGPL-2.1-or-later** for a few legacy files (e.g. `Eigen/src/Core/util/NonMPL2.h` gates these) | MPL-2.0 is permissive enough for MIT; the LGPL files are NOT pulled in by `` / `` (the only Eigen headers conformallab++ includes). | We define no preprocessor flag that activates the non-MPL2 code paths. The default Eigen build is pure MPL-2.0. | +| `libigl-2.6.0/` | [libigl](https://libigl.github.io) | 2.6.0 | **MPL-2.0** | Compatible with MIT distribution. | Only the viewer subsystem under `code/src/viewer/` uses libigl, and only when `-DWITH_VIEWER=ON`. The library headers and the CGAL wrapper headers do not depend on libigl. | +| `libigl-glad/` | [Glad](https://glad.dav1d.de/) (the generated OpenGL loader libigl ships) | bundled with libigl 2.6.0 | **MIT** (the generator's output is licensed permissively; the loader code itself is in the public domain via the original Khronos headers) | Compatible. | Built only with `-DWITH_VIEWER=ON`. | +| `glfw-3.4/` | [GLFW](https://www.glfw.org) | 3.4 | **zlib/libpng** | Permissive; compatible with MIT. | Built only with `-DWITH_VIEWER=ON`. See `code/deps/glfw-3.4/LICENSE.md` for the verbatim text. | +| `single_includes/json.hpp` | [nlohmann/json](https://github.com/nlohmann/json) | 3.x (header-only single-include) | **MIT** | Identical to ours. | The file itself carries the SPDX header `MIT`; see `code/deps/single_includes/json.hpp` first lines. | +| `tarballs/` | (build-artefact cache) | — | n/a | n/a | This directory just caches the downloaded source tarballs to avoid re-downloading on every clean build. The tarballs are bit-for-bit identical to the upstream releases. | + +## Auto-fetched (not vendored) + +These are pulled by CMake `FetchContent` at configure time. They are +**not** redistributed by conformallab++; the user's CMake fetches them +during build. We list them anyway for transparency. + +| Item | Upstream | Version | License | Fetched by | +|---|---|---|---|---| +| **GoogleTest** | https://github.com/google/googletest | v1.14.0 | **BSD-3-Clause** | `code/CMakeLists.txt` (test target only) | + +## System dependencies (required at build time, not redistributed) + +| Item | Where it lives | License | Purpose | +|---|---|---|---| +| **Boost** (header-only subset) | system package (`apt install libboost-dev`, etc.) | **Boost Software License 1.0** | Required by CGAL's BGL adapters (only when `WITH_CGAL=ON` or `WITH_CGAL_TESTS=ON`). | +| **C++17 standard library** | the compiler's libstdc++ / libc++ / msvc | LGPL-3.0 with exception / Apache 2.0 with LLVM exception / MSVC redist | normal compiler runtime. | + +## Summary for downstream packagers + +If you are packaging conformallab++ for a distribution, the practical +license matrix is: + +``` + binary you ship (CLI app, -DWITH_CGAL=ON) + ├── conformallab++ (MIT) + ├── CGAL (LGPL-3.0-or-later — comply with §4 LGPL: source + │ of CGAL must be obtainable or shipped) + ├── Eigen (MPL-2.0 — comply with §3 MPL: any modifications + │ must be released under MPL-2.0) + ├── libigl (MPL-2.0 — same as Eigen) + ├── GLFW (zlib/libpng — acknowledgement in product docs) + ├── Glad (MIT — preserve copyright notice) + └── Boost (headers) (BSL-1.0 — preserve copyright notice) + + header-only consumer (just #include our headers) + ├── conformallab++ (MIT) + ├── Eigen (MPL-2.0 transitively) + ├── CGAL (LGPL-3.0-or-later transitively) + └── Boost (headers) (BSL-1.0 transitively, only if you include any + CGAL/* header) +``` + +The header-only consumer typically doesn't trigger LGPL §4 obligations +because LGPL §3 explicitly permits use of LGPL'd material as +"templates, inline functions, macros" by an "Application" without +imposing copyleft on the Application — which is exactly the +header-only consumption pattern. + +If you have specific compliance questions, the upstream license texts +are authoritative; this file is a navigational aid. + +## How this file is maintained + +* Updated whenever a `code/deps/` tree is added, removed, or version-bumped. +* Cross-referenced by `doc/architecture/dependencies.md`. +* There is no CI gate that auto-verifies the SPDX entries against + upstream — that would require either an SBOM tool (e.g. `syft`, + `tern`) or a manual audit. The current policy is "review on + dep-tree change", logged in the commit message of the bump.