From 3b8fa9078e8ff722ab9b5235bc68ece2cf92a728 Mon Sep 17 00:00:00 2001 From: Ruben Romero Montes Date: Wed, 20 May 2026 13:38:42 +0200 Subject: [PATCH] fix(cargo): resolve workspace-inherited license in Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a Cargo.toml uses `license = { workspace = true }`, the tomlj library's getString() returns null because the value is an inline table, not a string. The license is silently dropped from the SBOM. Fix by using get() to retrieve the raw Object, checking instanceof String for direct values, and resolving from workspace.package.license when workspace inheritance is detected — following the existing version resolution pattern in parseCargoToml(). Fixes: TC-4528 Co-Authored-By: Claude Opus 4.6 --- .../trustifyda/providers/CargoProvider.java | 14 +++++++++++++- .../providers/CargoProviderLicenseTest.java | 16 ++++++++++++++++ .../Cargo.toml | 10 ++++++++++ .../Cargo.toml | 10 ++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance/Cargo.toml create mode 100644 src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance_no_license/Cargo.toml diff --git a/src/main/java/io/github/guacsec/trustifyda/providers/CargoProvider.java b/src/main/java/io/github/guacsec/trustifyda/providers/CargoProvider.java index 3b48fd56..d7764249 100644 --- a/src/main/java/io/github/guacsec/trustifyda/providers/CargoProvider.java +++ b/src/main/java/io/github/guacsec/trustifyda/providers/CargoProvider.java @@ -71,6 +71,9 @@ public final class CargoProvider extends Provider { private static final String PACKAGE_VERSION = "package.version"; private static final String PACKAGE_VERSION_WORKSPACE = "package.version.workspace"; private static final String WORKSPACE_PACKAGE_VERSION = "workspace.package.version"; + private static final String PACKAGE_LICENSE = "package.license"; + private static final String PACKAGE_LICENSE_WORKSPACE = "package.license.workspace"; + private static final String WORKSPACE_PACKAGE_LICENSE = "workspace.package.license"; private static final long TIMEOUT = Long.parseLong(System.getProperty("trustify.cargo.timeout.seconds", "5")); private final String cargoExecutable; @@ -671,7 +674,16 @@ private String readLicenseFromToml(TomlParseResult existingResult) { if (tomlResult.hasErrors()) { return null; } - String license = tomlResult.getString("package.license"); + String license = null; + Object licenseValue = tomlResult.get(PACKAGE_LICENSE); + if (licenseValue instanceof String) { + license = (String) licenseValue; + } else if (licenseValue != null) { + Boolean isWorkspaceLicense = tomlResult.getBoolean(PACKAGE_LICENSE_WORKSPACE); + if (Boolean.TRUE.equals(isWorkspaceLicense)) { + license = tomlResult.getString(WORKSPACE_PACKAGE_LICENSE); + } + } return LicenseUtils.getLicense(license, manifestPath); } catch (IOException e) { log.warning("Failed to read license from Cargo.toml: " + e.getMessage()); diff --git a/src/test/java/io/github/guacsec/trustifyda/providers/CargoProviderLicenseTest.java b/src/test/java/io/github/guacsec/trustifyda/providers/CargoProviderLicenseTest.java index 63bdaa31..2fcbb393 100644 --- a/src/test/java/io/github/guacsec/trustifyda/providers/CargoProviderLicenseTest.java +++ b/src/test/java/io/github/guacsec/trustifyda/providers/CargoProviderLicenseTest.java @@ -54,4 +54,20 @@ void readLicenseFromManifest_returns_null_when_no_license() { String license = provider.readLicenseFromManifest(); assertThat(license).isNull(); } + + /** Verifies that workspace-inherited license resolves from [workspace.package]. */ + @Test + void readLicenseFromManifest_returns_license_from_workspace_inheritance() { + var provider = createProvider("cargo_workspace_license_inheritance"); + String license = provider.readLicenseFromManifest(); + assertThat(license).isEqualTo("Apache-2.0"); + } + + /** Verifies graceful fallback when workspace inheritance has no license in workspace section. */ + @Test + void readLicenseFromManifest_returns_null_when_workspace_inheritance_but_no_workspace_license() { + var provider = createProvider("cargo_workspace_license_inheritance_no_license"); + String license = provider.readLicenseFromManifest(); + assertThat(license).isNull(); + } } diff --git a/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance/Cargo.toml b/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance/Cargo.toml new file mode 100644 index 00000000..d856f8d2 --- /dev/null +++ b/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test-project" +version = "1.0.0" +license = { workspace = true } + +[dependencies] +serde = "1.0" + +[workspace.package] +license = "Apache-2.0" diff --git a/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance_no_license/Cargo.toml b/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance_no_license/Cargo.toml new file mode 100644 index 00000000..a806d67a --- /dev/null +++ b/src/test/resources/tst_manifests/cargo/license/cargo_workspace_license_inheritance_no_license/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test-project" +version = "1.0.0" +license = { workspace = true } + +[dependencies] +serde = "1.0" + +[workspace.package] +version = "1.0.0"