Supply-chain features
A build is only as trustworthy as the code it pulls in. Jenesis has four build-time features for knowing and governing that closure: a software bill of materials that records exactly what you shipped, a licence check that gates the build on your policy, a vulnerability scan against the OSV advisory database, and the pinning that guarantees the bytes you build are the bytes you vetted. None of them needs a plugin or a build script - each turns on from a convention, over the same resolved dependency graph.
Software bill of materials
Every build emits a CycloneDX SBOM by default - a machine-readable list of every resolved component with
its version, content hash, and declared licence. There is nothing to enable and no external tool: the sbom
step runs before the jar is sealed and writes the document in one move, from the dependency graph, checksums,
and licences the build already has.
java build/jenesis/Project.java
The SBOM is a supply-chain counterpart to the dependencies selector (see Dependencies):
where that prints the resolved graph, the SBOM freezes it into a publishable artifact. It lands in three
places, one per consumer:
- Embedded in the jar, at
META-INF/sbom/<artifact>.cdx.json, so the bill of materials travels inside the artifact. The jar's manifest recordsSbom-Format: CycloneDXand anSbom-Locationheader pointing at it. - As a report, collected on
stageintotarget/stage/reports/output/sbom/<module>/alongside the other build reports. - As a Maven attachment, when a Maven repository is staged:
stagedrops<artifact>-<version>-cyclonedx.jsonnext to the pom and jar, soexportpublishes it to Maven Central as the conventional CycloneDX attached artifact.
Each component carries its pkg:maven/… package URL, its SHA-256 hash, and its licence, with a dependsOn
relationship back to the project. The document's metadata.component describes the project itself from the
POM - its description, licence, developers (as CycloneDX authors), and homepage and source repository (as
website and vcs references) - filling in only what the POM actually declares.
serialNumber is a UUID derived from the
document's own content, and no creation timestamp is written (a timestamp cannot be made
deterministic). A reproducible build reproduces the exact same SBOM, serial number included.
Choosing the format, or turning it off
An optional sbom.properties in the configuration folder selects the format:
format= |
Result |
|---|---|
json |
CycloneDX JSON - the default, also used when the file or the key is absent |
xml |
CycloneDX XML |
none |
disables the SBOM |
Any other value fails the build. To suppress the SBOM without adding a file, pass the default-true boolean
override -Djenesis.sbom.cyclonedx=false. Like every configuration file, sbom.properties is profile-aware,
so a release profile can select the XML format while everyday builds keep JSON (see
Configuration).
Licence compliance
The licence check gates the build on the licences of its resolved dependencies. It stays off until a
licensing.properties file exists in the configuration folder (build.jenesis/ under the project root by
default). The file's presence enables the check; its contents configure it.
The check runs over the shipped (main compile/runtime) dependencies; in-build snapshots and build-tool
closures are excluded. Each dependency's declared licence is normalised to a canonical SPDX identifier and a
category. A dependency that declares no licence is read from its jar instead: its embedded CycloneDX SBOM
first, then the OSGi Bundle-License header, then a META-INF/LICENSE text file matched heuristically. The
verdicts are written to reports/compliance/licenses.txt, one line per dependency (OK, DENIED, MISSING,
WARN, or UNKNOWN):
mysql/mysql-connector-java/5.1.49 [DENIED] The GNU General Public License, Version 2
org.apache.commons/commons-lang3/3.14.0 [OK] Apache-2.0
The file's keys:
allowed(comma-separated) fails any dependency whose licence is not on the list. Entries match the SPDX id, the category, or the raw name/URL:Apache-2.0,Apache, orpermissiveall match an Apache licence, whilestrong-copyleftmatches the GPL family. A dependency with several licences passes if any one is allowed, because Maven lists licences disjunctively. Adeniedlist of the same syntax rejects matches outright.unknown=ignore|warn|failgates a missing licence, defaultfail: "no declared licence" is legally all-rights-reserved, so the strict default refuses it.override.<coordinate>curates a wrong or empty declaration, keyed by the dependency coordinate (themaven/prefix, with or without a version):override.maven/org.example/widget=Apache-2.0.
# build.jenesis/licensing.properties
allowed=permissive,weak-copyleft
unknown=fail
The category keywords are permissive, weak-copyleft, strong-copyleft, network-copyleft, and
public-domain. An unrecognised key fails the build. To skip the check, remove the file.
Teaching it about a licence (optional)
Normalisation draws on comprehensive built-in tables, so most projects need no configuration. To teach the
check about a licence it does not know - a differently worded name, or an identifier that lacks a category -
drop an optional spdx.properties in the configuration folder. It uses one prefixed key space:
# build.jenesis/spdx.properties
alias/A Company License=Apache-2.0
category/Apache-2.0=permissive
alias/<declared name> normalises a licence name as written in a POM to its canonical SPDX id;
category/<SPDX id> classifies an identifier. Each entry appends to the built-in tables rather than
replacing them, and the same classification feeds both the licence check and the SBOM's licence identifiers.
It is distinct from licensing.properties, which is the enforcement policy, not the classification.
Vulnerability scanning
The vulnerability check gates the build on the known vulnerabilities of its resolved dependencies. Like the
licence check, it stays off until its file, vulnerability.properties, exists in the configuration
folder. With the file present, the build queries the public OSV.dev advisory database -
no account, no API key - for the resolved coordinates, writes every match to
reports/compliance/vulnerabilities.txt, and applies your threshold:
# build.jenesis/vulnerability.properties
severity=critical
The keys:
severity=low|medium|high|criticalis the threshold; a matched advisory at or above it is flagged.warn=true|false(defaultfalse): a flagged advisory warns (reported, build passes) whentrue, or fails the build whenfalse.osv.endpoint(optional) overrides the OSV endpoint (defaulthttps://api.osv.dev).
vulnerability.properties is present. Remove the file to keep the build fully
offline.
An unrecognised key fails the build. The licence and vulnerability checks are two halves of the same
compliance step, each turned on by the presence of its own file, so you can run either, both, or neither.
To keep both files in place but skip both checks for a single build, pass the default-true override
-Djenesis.compliance=false.
Hardening the whole build
The SBOM, licence, and vulnerability checks all describe the closure they resolve. Pinning is what makes
that closure trustworthy in the first place: Jenesis pins every dependency by version and by the SHA-256
checksum of the jar, and verifies each download against its pin. A coordinate whose bytes do not match its
recorded checksum is rejected outright, which is exactly what happens if a repository serves a swapped or
compromised artifact. Pinning & bills of materials covers how to record pins, how
-Djenesis.dependency.pin=strict requires them, and how to refresh a frozen closure deliberately. A hardened
supply chain layers the checks above on top of a fully pinned, strict build.
Why strict pinning matters
Only the resolved artifacts carry a checksum; the pom.xml files read during resolution are not pinned,
because some servers apply harmless whitespace or line-ending changes that would produce spurious mismatches.
That leaves one gap: a tampered POM could try to introduce a dependency the jar checksums do not cover.
Strict pinning closes it. Any dependency a POM newly adds arrives as a coordinate with no pin, which
strict mode rejects, so a manipulated POM cannot quietly pull in an unverified artifact. This is why strict
pinning is recommended for builds in unsecured environments and for releases.