Dependencies
Every library njMule uses is pinned to one version, locked, and checked against a known SHA-256 checksum before Gradle uses it. This page explains where versions live, which libraries are welcome, and the exact steps after you change a version.
Where versions live
gradle/libs.versions.toml
is the version catalog of the whole build:
[versions]: Java (java = "25"), the Node.js release of the interface, the desktop window's Tauri command line and this site (nodejs, an LTS line), the runtime and test libraries, and the build tools (Checkstyle, palantir-java-format, Error Prone, SpotBugs, FindSecBugs, JaCoCo).[libraries]: every library, including the Gradle plugins that the convention plugin inbuild-logic/applies (Spotless, Error Prone, SpotBugs).[plugins]: the other Gradle plugins (GraalVM Native Build Tools, Shadow, CycloneDX, the license report, OWASP dependency-check, SonarQube, the Node.js plugin).
The modules name libraries only through the catalog (libs.guava, libs.jetty.server), never with
a version of their own. Gradle itself is pinned in gradle/wrapper/gradle-wrapper.properties, with
the SHA-256 of its distribution.
The libraries come from Maven Central only, the Gradle plugins from the Gradle Plugin Portal. The
settings add one more repository, https://nodejs.org/dist/, limited to the Node.js archives.
Choosing a library
- The JDK first, then a well-known library. Before you write a utility, codec, parser or data structure, check whether the JDK or a maintained open-source library already does it. Write your own only for what is specific to eD2K and Kad, or when nothing suitable exists or fits the constraints below, and say why in a comment or the commit message. The benchmarks keep some of the measurements behind such choices.
- A license compatible with the GPL 3.0: MIT, BSD, Apache-2.0, LGPL, GPL-2.0-or-later and the like. See Licenses below.
- Native-image friendly: no undeclared reflection, no dynamic proxies (Native images).
- Always the latest stable version. Check Maven Central and the Gradle Plugin Portal before you add or bump one.
palantir-java-format is pinned to the newest version that Spotless supports, which may be older than the newest palantir-java-format release.
Locking and verification
Two mechanisms make every build resolve exactly the same files:
- Dependency locking. Every resolved version is written to the
gradle.lockfileof each project, plusbuildscript-gradle.lockfileandsettings-gradle.lockfileat the root and the lock files ofbuild-logic/. A resolution that differs from the lock files fails the build. - Dependency verification. Every downloaded artifact, POMs and Gradle module metadata included,
is checked against its SHA-256 in
gradle/verification-metadata.xml. Any difference fails the build. The file also lists the Node.js archives of the five platforms the interface and the site may be built on (Windows x64, Linux x64 and arm64, macOS x64 and arm64), not only yours, with the checksums Node.js publishes in itsSHASUMS256.txt.
After changing a version
When you change libs.versions.toml, a plugin version or Gradle itself:
-
Rewrite the lock files and the checksums in one run:
./gradlew --no-configuration-cache --refresh-dependencies --write-verification-metadata sha256 \--write-locks spotlessCheck :njmule-app:collectReachabilityMetadata \:njmule-app:generateLicenseReport cyclonedxBomThe tasks in the command make Gradle resolve what a plain build may not: the formatter that Spotless downloads, the GraalVM reachability metadata repository of the native build, and what the license report and the SBOM read.
-
Delete the entries of the versions no longer used from
verification-metadata.xml. -
Review the new checksums before you commit them.
-
After a change of
nodejs, add the new Node.js archives of all five platforms toverification-metadata.xmlwith the checksums of Node.js'sSHASUMS256.txt, as the existing entries are.
Without it, Gradle leaves out of verification-metadata.xml the parent POMs and BOMs it already
holds in its local cache. Your build still passes, but the CI starts with an empty cache, downloads
them and fails on their missing checksums.
Dependabot's pull requests change versions without these steps: run the same command on their branch, commit the rewritten files there, and squash-merge the pull request like any other once its checks pass.
npm packages
The interface (njmule-ui), the desktop window's Tauri command line (njmule-desktop) and this site
(website) are npm projects inside the Gradle build. Gradle downloads the pinned Node.js and runs
npm ci, which installs exactly what package-lock.json holds. Their .npmrc files set:
| Setting | Effect |
|---|---|
ignore-scripts=true | no package runs code while it is installed |
save-exact=true | npm install <package> writes an exact version, never a range |
engine-strict=true | npm refuses a Node.js older than the engines field asks (24 or newer) |
audit=false, fund=false | no audit or funding requests while installing |
To add or update a package, run npm in that folder (with the Node.js Gradle downloaded into its
.gradle/nodejs folder, or your own Node.js 24 or newer), then commit package.json and
package-lock.json together. A task that runs npm ci empties node_modules first: stop a Vite
development server before you run one.
Rust crates
The desktop window's shell (njmule-desktop/src-tauri) is a Cargo project. Rust itself is pinned by
rust-toolchain.toml, which rustup installs on first use, with rustfmt and Clippy. The crates are
pinned in Cargo.toml, the Tauri crates and plugins to exact versions (=2.12.5), and locked with
their checksums in Cargo.lock, which the CI enforces with --locked. After changing a crate, let
Cargo rewrite Cargo.lock and commit both files together.
Dependabot
.github/dependabot.yml looks
for updates once a week:
| Ecosystem | Where | Commit prefix |
|---|---|---|
| Gradle | the root build and the version catalog | chore(deps) |
| GitHub Actions | the workflows, whose actions are pinned by commit hash | ci(deps) |
| Docker | the base images of packaging/docker, pinned by digest | build(deps) |
| npm | website/package-lock.json, with the Docusaurus packages and the two OpenAPI docs packages grouped | docs(deps) |
| npm | njmule-ui/package-lock.json, with the Vue, TanStack and Vite/Vitest packages grouped | chore(deps) |
| npm | njmule-desktop/package-lock.json, the Tauri command line | chore(deps) |
| Cargo | njmule-desktop/src-tauri/Cargo.lock, with the Tauri crates grouped | chore(deps) |
The downloads the workflows make outside Gradle (GraalVM, the musl toolchain, nfpm) are pinned too, each checked against its SHA-256 in the workflow file.
Licenses
njMule is licensed under the GPL 3.0 or later, so everything it ships must be compatible with it. When you add third-party code or an asset:
- keep its original notices;
- record its origin and license in
REUSE.tomlwhen the file cannot carry an SPDX header itself, and add its license text toLICENSES/; - add it to
NOTICE, which lists the components of the binary distributions.
The full lists with versions are generated: THIRD-PARTY.txt by
./gradlew :njmule-app:generateLicenseReport, and the interface's THIRD-PARTY.md by its Vite
build, which ships it beside the interface. Test-only libraries and build tools are not
distributed.
Related pages
- Building
- Code style: SPDX headers and REUSE.
- Releases: the SBOM attached to every release.