mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
# Description of Changes This change adds a version-scoped override mechanism for dependencies whose published metadata does not expose a detectable license. - Added `app/license-overrides.json` with verified Apache License 2.0 metadata for: - `com.hubspot.immutables:immutables-exceptions:1.9` - `com.hubspot:algebra:1.5` - Added `ModuleLicenseOverrideFilter` as custom `buildSrc` logic for the Gradle dependency license report plugin. - Applied overrides only when the exact `group:artifact:version` matches and no usable license metadata was detected. - Added automatic maintenance of the override file: - Removes overrides when the dependency is no longer resolved. - Removes overrides when the dependency starts publishing valid license metadata. - Migrates stale overrides to newer unresolved versions and clears their metadata for re-verification. - Adds null-valued placeholders for newly detected dependencies without license metadata. - Preserves populated overrides for newer versions when already present. - Added Gradle version-aware dependency ordering for override migration. - Registered `app/license-overrides.json` as an input for license-report and license-check preparation tasks. - Centralized the dependency license report plugin version in `buildSrc`. - Added unit tests covering override application, cleanup, migration, exact-version matching, concurrent versions, placeholder generation, and numeric version ordering. - Added documentation describing the override lifecycle, verification requirements, maintenance workflow, and validation commands. - Replaced broad null-license allowances for the two HubSpot modules with explicit Apache License 2.0 metadata. - Added accepted GNU Lesser General Public License name variants encountered in dependency metadata. The change was made because some dependencies have known upstream licenses but do not publish license metadata in a form detected by the Gradle license report plugin. Previously, these dependencies were permitted through module-specific null-license exceptions, leaving incomplete information in the generated report. The new mechanism supplies verified metadata without overriding valid metadata published by dependencies. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details.
169 lines
7.6 KiB
Markdown
169 lines
7.6 KiB
Markdown
# Dependency license overrides
|
|
|
|
The backend dependency license report is generated by the
|
|
[`com.github.jk1.dependency-license-report`](https://github.com/jk1/Gradle-License-Report)
|
|
Gradle plugin. Most license information is read from dependency POM files, manifests, or packaged
|
|
license files. Some artifacts do not publish license metadata in a form the plugin can detect, even
|
|
though the artifact has a known license.
|
|
|
|
This directory contains the build logic used to provide narrowly scoped fallback license metadata
|
|
for those artifacts.
|
|
|
|
## Files
|
|
|
|
- `build.gradle` makes version 3.1.4 of the license report plugin available to the custom build
|
|
logic. The root build applies that plugin without a second version declaration so both use the
|
|
same classpath.
|
|
- `src/main/groovy/stirling/software/gradle/ModuleLicenseOverrideFilter.groovy` implements the
|
|
plugin's `DependencyFilter` interface.
|
|
- `../app/license-overrides.json` contains the actual module-specific fallback values.
|
|
- `../app/allowed-licenses.json` defines which detected or supplied licenses are accepted by
|
|
`checkLicense`.
|
|
|
|
## How it works
|
|
|
|
The root `build.gradle` passes `app/license-overrides.json` to
|
|
`ModuleLicenseOverrideFilter`:
|
|
|
|
```groovy
|
|
filters = [new ModuleLicenseOverrideFilter(moduleLicenseOverridesFile)]
|
|
```
|
|
|
|
For every dependency discovered by the license plugin, the filter builds an identifier in this
|
|
format:
|
|
|
|
```text
|
|
group:artifact:version
|
|
```
|
|
|
|
The filter applies a populated override only when both conditions are true:
|
|
|
|
1. The complete identifier, including the version, exists in `app/license-overrides.json`.
|
|
2. The plugin did not discover a non-empty license name for that dependency.
|
|
|
|
When both conditions match, the filter adds the configured license as fallback manifest metadata.
|
|
The normal report renderer and `checkLicense` then consume that metadata in the same way as
|
|
metadata discovered from the dependency itself.
|
|
|
|
An override never replaces a license that the plugin already detected. Updating a dependency also
|
|
does not silently reuse the override because a different version produces a different identifier.
|
|
|
|
Overrides are temporary fallbacks, not a permanent license catalog. If the plugin starts detecting
|
|
the original license for an overridden module, the filter automatically removes that exact entry
|
|
from `app/license-overrides.json` and logs the cleanup. When the overridden version is no longer
|
|
resolved, a newer resolved version takes its place: if it declares a license, the stale entry is
|
|
removed; otherwise the entry moves to the new exact version and its values are cleared for
|
|
re-verification. An already populated entry for the new version is preserved. If no higher version
|
|
is resolved, the unused override is removed instead.
|
|
|
|
Because the report aggregates several projects and configurations, multiple versions of the same
|
|
`group:artifact` can be present at once. An override is retained whenever its exact version is still
|
|
resolved. Only when that exact version is absent may the filter treat a higher version as an update;
|
|
version ordering then follows Gradle's own dependency version comparator. Overrides for dependency
|
|
versions that are no longer resolved and have no higher replacement are deleted automatically.
|
|
|
|
The filter also records every resolved dependency without detected license metadata that has no
|
|
override yet. It writes a placeholder with `null` values for `name`, `url`, and `projectUrl`.
|
|
Placeholders deliberately do not affect the generated report until `name` is filled in. This makes
|
|
new missing metadata visible in the source-controlled override file instead of only in a generated
|
|
report. Review and fill or remove every new placeholder before committing the resulting JSON.
|
|
|
|
## Adding an override
|
|
|
|
First verify the license from an authoritative source such as the upstream repository, the
|
|
published artifact metadata, or the license file shipped inside the artifact. Do not infer a
|
|
license from the organization name or from a related artifact.
|
|
|
|
Add an entry to `app/license-overrides.json`:
|
|
|
|
```json
|
|
{
|
|
"com.example:example-library:1.2.3": {
|
|
"name": "Apache License, Version 2.0",
|
|
"url": "https://www.apache.org/licenses/LICENSE-2.0",
|
|
"projectUrl": "https://github.com/example/example-library/tree/0123456789abcdef0123456789abcdef01234567"
|
|
}
|
|
}
|
|
```
|
|
|
|
The key must contain the exact resolved version. `name` must be non-empty for the override to be
|
|
applied. `url` should point to the canonical license text. `projectUrl` must point to the immutable
|
|
Git tree for the exact module version, using the commit hash at which that version was introduced:
|
|
|
|
```text
|
|
https://github.com/<owner>/<repository>/tree/<full-commit-hash>
|
|
```
|
|
|
|
Do not use the repository's default branch or another moving URL. See the existing entries in
|
|
`app/license-overrides.json` for concrete examples.
|
|
|
|
If the license name is not already accepted, add a suitably narrow rule to
|
|
`app/allowed-licenses.json`. Adding an override and allowing a license are separate operations:
|
|
|
|
- `license-overrides.json` supplies missing metadata for a specific artifact version.
|
|
- `allowed-licenses.json` defines the policy enforced by `checkLicense`.
|
|
|
|
## Updating a dependency
|
|
|
|
When an overridden dependency changes version:
|
|
|
|
1. Verify the license for the new version again.
|
|
2. Run the license report so the filter can move the old key or add a placeholder for the new full
|
|
`group:artifact:version` key.
|
|
3. Re-verify and fill the license values and the version's immutable Git-tree `projectUrl`; moved
|
|
values are intentionally cleared because a license conclusion for one release is not assumed
|
|
for another.
|
|
4. Regenerate and inspect the report.
|
|
|
|
If the new artifact publishes usable license metadata, no override is necessary. The next license
|
|
report or license check removes the old entry from `app/license-overrides.json` automatically. The
|
|
file must contain only overrides that are still needed.
|
|
|
|
## Verification
|
|
|
|
Run the filter unit tests:
|
|
|
|
```powershell
|
|
.\gradlew.bat -p buildSrc test
|
|
```
|
|
|
|
The tests use `com.example:example-library` versions 1.4 and 1.7 to cover the missing
|
|
metadata fallback, placeholder creation, version migration, preservation of a populated newer
|
|
override, automatic cleanup after license metadata appears, exact-version matching, and concurrent
|
|
resolved versions. They also verify removal when a dependency version disappears. A separate `1.9`
|
|
to `1.11.0` case verifies numeric Gradle version ordering.
|
|
|
|
Run the normal backend license workflow from the repository root:
|
|
|
|
```powershell
|
|
task backend:licenses:generate
|
|
```
|
|
|
|
Then inspect:
|
|
|
|
- `build/reports/dependency-license/index.json` for the rendered module, version, license name, and
|
|
URL.
|
|
- `build/reports/dependency-license/dependencies-without-allowed-license.json` when `checkLicense`
|
|
reports a policy failure.
|
|
|
|
Also run the backend quality gate after changing the filter or its build wiring:
|
|
|
|
```powershell
|
|
task backend:check
|
|
```
|
|
|
|
The override JSON is registered as an input of `generateLicenseReport` and
|
|
`checkLicensePreparation`, so changing the file invalidates the corresponding Gradle task outputs.
|
|
|
|
## What not to do
|
|
|
|
- Do not use an unversioned key. It cannot match the filter and would make the intended scope
|
|
ambiguous.
|
|
- Do not use an override to replace valid license metadata published by a dependency.
|
|
- Do not add an empty license to `allowed-licenses.json` merely to silence `checkLicense`; that
|
|
would still leave the generated report without useful license information.
|
|
- Do not exclude a dependency from the report solely because it is transitive. Runtime transitive
|
|
dependencies are still distributed components and their licenses remain relevant.
|
|
- Do not edit generated files under `build/reports/dependency-license` or the copied static license
|
|
report by hand.
|