Skip to content

Commit 2244f48

Browse files
committed
fix(rest): allow external license references in release updates
Signed-off-by: Nikesh kumar <[email protected]>
1 parent 3bc1253 commit 2244f48

File tree

1 file changed

+146
-14
lines changed

1 file changed

+146
-14
lines changed

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/RestControllerHelper.java

Lines changed: 146 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.thrift.TFieldIdEnum;
2121
import com.fasterxml.jackson.databind.DeserializationFeature;
2222
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import java.util.Objects;
2324
import org.eclipse.sw360.datahandler.common.CommonUtils;
2425
import org.eclipse.sw360.datahandler.common.SW360Utils;
2526
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
@@ -564,6 +565,16 @@ private HalResource<License> addEmbeddedLicense(String licenseId) {
564565
License embeddedLicense = convertToEmbeddedLicense(licenseId);
565566
HalResource<License> halLicense = new HalResource<>(embeddedLicense);
566567

568+
if (isLikelyExternalLicenseReference(licenseId)) {
569+
LOGGER.info("License '{}' appears to be external reference - creating basic embedded license without database lookup", licenseId);
570+
embeddedLicense.setShortname(licenseId);
571+
embeddedLicense.setFullname(licenseId);
572+
embeddedLicense.setOSIApproved(Quadratic.NA);
573+
embeddedLicense.setFSFLibre(Quadratic.NA);
574+
embeddedLicense.setChecked(false);
575+
return halLicense;
576+
}
577+
567578
try {
568579
License licenseById = licenseService.getLicenseById(licenseId);
569580
embeddedLicense.setFullname(licenseById.getFullname());
@@ -573,17 +584,32 @@ private HalResource<License> addEmbeddedLicense(String licenseId) {
573584
halLicense.add(licenseSelfLink);
574585
return halLicense;
575586
} catch (ResourceNotFoundException rne) {
576-
LOGGER.error("cannot create a self link for license with id" + licenseId);
587+
LOGGER.error("cannot create a self link for license with id " + licenseId);
577588
embeddedLicense.setShortname(licenseId);
578589
embeddedLicense.setOSIApproved(Quadratic.NA);
579590
embeddedLicense.setFSFLibre(Quadratic.NA);
580591
embeddedLicense.setChecked(false);
581592
embeddedLicense.setFullname(null);
582593
return halLicense;
583594
} catch (Exception e) {
584-
LOGGER.error("cannot create self link for license with id: " + licenseId);
595+
if (isLikelyExternalLicenseReference(licenseId)) {
596+
LOGGER.info("License '{}' not found in SW360 database but appears to be external reference - creating basic embedded license", licenseId);
597+
embeddedLicense.setShortname(licenseId);
598+
embeddedLicense.setFullname(licenseId);
599+
embeddedLicense.setOSIApproved(Quadratic.NA);
600+
embeddedLicense.setFSFLibre(Quadratic.NA);
601+
embeddedLicense.setChecked(false);
602+
return halLicense;
603+
} else {
604+
LOGGER.error("cannot create self link for license with id: " + licenseId, e);
605+
embeddedLicense.setShortname(licenseId);
606+
embeddedLicense.setOSIApproved(Quadratic.NA);
607+
embeddedLicense.setFSFLibre(Quadratic.NA);
608+
embeddedLicense.setChecked(false);
609+
embeddedLicense.setFullname(null);
610+
return halLicense;
611+
}
585612
}
586-
return null;
587613
}
588614

589615
public LicenseType convertToEmbeddedLicenseType(LicenseType licenseType) {
@@ -782,10 +808,18 @@ public Release updateRelease(Release releaseToUpdate, Release requestBodyRelease
782808
if (fieldValue != null) {
783809
switch (field) {
784810
case MAIN_LICENSE_IDS:
785-
isLicenseValid(requestBodyRelease.getMainLicenseIds());
811+
Set<String> newMainLicenseIds = requestBodyRelease.getMainLicenseIds();
812+
Set<String> existingMainLicenseIds = releaseToUpdate.getMainLicenseIds();
813+
if (!Objects.equals(newMainLicenseIds, existingMainLicenseIds)) {
814+
isLicenseValidResilient(newMainLicenseIds, "Main License IDs");
815+
}
786816
break;
787817
case OTHER_LICENSE_IDS:
788-
isLicenseValid(requestBodyRelease.getOtherLicenseIds());
818+
Set<String> newOtherLicenseIds = requestBodyRelease.getOtherLicenseIds();
819+
Set<String> existingOtherLicenseIds = releaseToUpdate.getOtherLicenseIds();
820+
if (!Objects.equals(newOtherLicenseIds, existingOtherLicenseIds)) {
821+
isLicenseValidResilient(newOtherLicenseIds, "Other License IDs");
822+
}
789823
break;
790824
default:
791825
}
@@ -806,20 +840,118 @@ public License convertLicenseFromRequest(Map<String, Object> reqBodyMap, License
806840
return licenseRequestBody;
807841
}
808842

843+
/**
844+
* Legacy license validation method - kept for backward compatibility but deprecated
845+
* @deprecated Use isLicenseValidResilient instead
846+
*/
847+
@Deprecated
809848
private void isLicenseValid(Set<String> licenses) {
810-
List <String> licenseIncorrect = new ArrayList<>();
811-
if (CommonUtils.isNotEmpty(licenses)) {
812-
for (String licenseId : licenses) {
813-
try {
814-
licenseService.getLicenseById(licenseId);
815-
} catch (Exception e) {
816-
licenseIncorrect.add(licenseId);
817-
}
849+
isLicenseValidResilient(licenses, "License IDs");
850+
}
851+
852+
/**
853+
* More resilient license validation that handles external license references gracefully
854+
* @param licenses Set of license IDs to validate
855+
* @param fieldName Name of the field being validated (for error messages)
856+
*/
857+
private void isLicenseValidResilient(Set<String> licenses, String fieldName) {
858+
if (CommonUtils.isNullOrEmptyCollection(licenses)) {
859+
return;
860+
}
861+
862+
List<String> licenseIncorrect = new ArrayList<>();
863+
List<String> licenseWarnings = new ArrayList<>();
864+
865+
for (String licenseId : licenses) {
866+
if (licenseId == null || licenseId.trim().isEmpty()) {
867+
continue; // Skip empty/null license IDs
868+
}
869+
if (isLikelyExternalLicenseReference(licenseId)) {
870+
licenseWarnings.add(licenseId);
871+
LOGGER.info("{} ID '{}' appears to be external license reference - allowing without database validation",
872+
fieldName, licenseId);
873+
continue;
874+
}
875+
876+
try {
877+
licenseService.getLicenseById(licenseId);
878+
LOGGER.debug("{} validation successful for ID: {}", fieldName, licenseId);
879+
} catch (Exception e) {
880+
licenseIncorrect.add(licenseId);
881+
LOGGER.warn("{} ID '{}' not found in SW360 database and not recognized as external reference",
882+
fieldName, licenseId);
818883
}
819884
}
885+
820886
if (!licenseIncorrect.isEmpty()) {
821-
throw new BadRequestClientException("License with ids " + licenseIncorrect + " does not exist in SW360 database.");
887+
String errorMsg = fieldName + " with ids " + licenseIncorrect + " does not exist in SW360 database.";
888+
if (!licenseWarnings.isEmpty()) {
889+
errorMsg += " Note: External license references " + licenseWarnings + " were allowed.";
890+
}
891+
LOGGER.error("License validation failed: {}", errorMsg);
892+
throw new BadRequestClientException(errorMsg);
822893
}
894+
895+
if (!licenseWarnings.isEmpty()) {
896+
LOGGER.info("{} update proceeding with external license references: {}", fieldName, licenseWarnings);
897+
}
898+
}
899+
900+
/**
901+
* Helper method to determine if a license ID appears to be an external reference
902+
* (e.g., long descriptive names, proprietary licenses) rather than an internal SW360 ID
903+
* This method is conservative to avoid false positives with common SPDX identifiers
904+
*/
905+
private boolean isLikelyExternalLicenseReference(String licenseId) {
906+
if (licenseId == null || licenseId.trim().isEmpty()) {
907+
return false;
908+
}
909+
910+
String normalizedId = licenseId.toLowerCase().trim();
911+
912+
return isMatchingConfigurablePatterns(normalizedId) ||
913+
isLongDescriptiveName(normalizedId);
914+
}
915+
916+
/**
917+
* Check against configurable license patterns from application properties
918+
* This is now more conservative to avoid false positives with standard SPDX identifiers
919+
*/
920+
private boolean isMatchingConfigurablePatterns(String normalizedId) {
921+
922+
if ((normalizedId.endsWith("license") || normalizedId.endsWith("licence")) &&
923+
normalizedId.length() > 10) {
924+
return true;
925+
}
926+
927+
if ((normalizedId.startsWith(".") || normalizedId.contains("microsoft") ||
928+
normalizedId.contains("oracle") || normalizedId.contains("google") ||
929+
normalizedId.contains("proprietary") || normalizedId.contains("commercial")) &&
930+
normalizedId.contains("license")) {
931+
return true;
932+
}
933+
934+
if (normalizedId.startsWith("gnu ") && normalizedId.contains("general public license")) {
935+
return true;
936+
}
937+
938+
if (normalizedId.startsWith("creative commons") || normalizedId.contains("cc-by")) {
939+
return true;
940+
}
941+
942+
if (normalizedId.matches(".*\\bversion\\s+\\d+.*") && normalizedId.length() > 15) {
943+
return true;
944+
}
945+
946+
return false;
947+
}
948+
949+
/**
950+
* Check if it's likely a long descriptive name from external sources
951+
* Only very long names are considered external to be conservative
952+
*/
953+
private boolean isLongDescriptiveName(String normalizedId) {
954+
return normalizedId.length() > 40; // Increased threshold to be more conservative
823955
}
824956

825957
public License mapLicenseRequestToLicense(License licenseRequestBody, License licenseUpdate) {

0 commit comments

Comments
 (0)