Skip to content

Commit 96a0e8c

Browse files
committed
chore: simplify licenseCheck
Signed-off-by: Ruben Romero Montes <rromerom@redhat.com>
1 parent ca48015 commit 96a0e8c

2 files changed

Lines changed: 39 additions & 74 deletions

File tree

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as url from 'url';
99

1010
export { parseImageRef } from "./oci_image/utils.js";
1111
export { ImageRef } from "./oci_image/images.js";
12-
export { getProjectLicense, getProjectLicenseFromManifest as getProjectLicenseFromManifestOnly, findLicenseFilePath, identifyLicenseViaBackend, getLicensesByPurl, getLicenseDetails, licenseMapFromAnalysisReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility, extractPurlsFromSbom } from "./license/index.js";
12+
export { getProjectLicense, getProjectLicenseFromManifest as getProjectLicenseFromManifestOnly, findLicenseFilePath, identifyLicenseViaBackend, getLicensesByPurl, getLicenseDetails, licenseMapFromAnalysisReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility } from "./license/index.js";
1313

1414
export default { componentAnalysis, stackAnalysis, imageAnalysis, validateToken }
1515

src/license/index.js

Lines changed: 38 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,6 @@ export { getProjectLicense, getProjectLicenseFromManifest, findLicenseFilePath,
1010
export { licenseMapFromAnalysisReport, normalizeLicensesResponse, getLicensesByPurl, getLicenseDetails } from './licenses_api.js';
1111
export { getCompatibility } from './compatibility.js';
1212

13-
/**
14-
* Extract all component purls from a CycloneDX SBOM JSON string (excluding root if desired).
15-
* @param {string} sbomContent - CycloneDX JSON string
16-
* @param {boolean} [excludeRoot=true] - if true, exclude the root component's purl from the list
17-
* @returns {string[]}
18-
*/
19-
export function extractPurlsFromSbom(sbomContent, excludeRoot = true) {
20-
let obj;
21-
try {
22-
obj = typeof sbomContent === 'string' ? JSON.parse(sbomContent) : sbomContent;
23-
} catch {
24-
return [];
25-
}
26-
const components = obj?.components;
27-
if (!Array.isArray(components)) return [];
28-
29-
const rootRef = obj?.metadata?.component?.["bom-ref"] ?? obj?.metadata?.component?.purl;
30-
const purls = components
31-
.map(c => c.purl || c["bom-ref"] || c.bomRef)
32-
.filter(Boolean);
33-
34-
if (excludeRoot && rootRef) {
35-
const rootPurl = typeof rootRef === 'string' ? rootRef : rootRef?.purl;
36-
return purls.filter(p => p !== rootPurl);
37-
}
38-
return purls;
39-
}
40-
4113
/**
4214
* Run full license check: resolve project license (with backend identification and details),
4315
* get dependency licenses from analysis report, and compute incompatibilities.
@@ -50,80 +22,77 @@ export function extractPurlsFromSbom(sbomContent, excludeRoot = true) {
5022
* @returns {Promise<{ projectLicense: { manifest: Object|null, file: Object|null, mismatch: boolean }, incompatibleDependencies: Array<{ purl: string, licenses: string[], category?: string, reason: string }>, error?: string }>}
5123
*/
5224
export async function runLicenseCheck(sbomContent, manifestPath, backendUrl, opts = {}, analysisResult = null) {
53-
// Get project license from manifest (always available)
25+
// Resolve project license from manifest and LICENSE file
5426
const projectLicense = getProjectLicense(manifestPath, opts);
5527

56-
// Try to get more accurate LICENSE file identification from backend
57-
let projectLicenseFromFileBackend = null;
28+
// Try backend identification for LICENSE file (more accurate than local pattern matching)
5829
const licenseFilePath = findLicenseFilePath(manifestPath);
30+
let backendFileId = null;
5931
if (licenseFilePath && backendUrl) {
6032
try {
61-
projectLicenseFromFileBackend = await identifyLicense(licenseFilePath, backendUrl, opts);
33+
backendFileId = await identifyLicense(licenseFilePath, backendUrl, opts);
6234
} catch {
63-
// Fall back to local detection (already in projectLicense.fromFile)
35+
// Fall back to local detection
6436
}
6537
}
6638

67-
// Use backend identification if available, otherwise use local detection
68-
const finalFromFile = projectLicenseFromFileBackend || projectLicense.fromFile;
69-
const finalMismatch = Boolean(
70-
projectLicense.fromManifest && finalFromFile &&
71-
projectLicense.fromManifest.toLowerCase() !== finalFromFile.toLowerCase()
72-
);
39+
// Determine final license identifiers
40+
const manifestSpdx = projectLicense.fromManifest;
41+
const fileSpdx = backendFileId || projectLicense.fromFile;
42+
const mismatch = Boolean(manifestSpdx && fileSpdx && manifestSpdx.toLowerCase() !== fileSpdx.toLowerCase());
7343

74-
// Fetch detailed license info from backend for both manifest and file licenses
75-
let manifestLicenseInfo = null;
76-
let fileLicenseInfo = null;
44+
// Fetch detailed license info from backend (avoid duplicate calls if same license)
45+
const licenseDetailsCache = new Map();
7746

78-
if (projectLicense.fromManifest && backendUrl) {
79-
try {
80-
manifestLicenseInfo = await getLicenseDetails(projectLicense.fromManifest, backendUrl, opts);
81-
} catch {
82-
// Backend might not have this license; keep as null
83-
}
84-
}
47+
async function getDetails(spdxId) {
48+
if (!spdxId || !backendUrl) return null;
49+
if (licenseDetailsCache.has(spdxId)) return licenseDetailsCache.get(spdxId);
8550

86-
if (finalFromFile && backendUrl) {
8751
try {
88-
fileLicenseInfo = await getLicenseDetails(finalFromFile, backendUrl, opts);
52+
const details = await getLicenseDetails(spdxId, backendUrl, opts);
53+
licenseDetailsCache.set(spdxId, details);
54+
return details;
8955
} catch {
90-
// Backend might not have this license; keep as null
56+
return null;
9157
}
9258
}
9359

94-
const purls = extractPurlsFromSbom(sbomContent, true);
60+
const manifestLicenseInfo = await getDetails(manifestSpdx);
61+
const fileLicenseInfo = await getDetails(fileSpdx);
62+
63+
// Extract dependency purls from SBOM (exclude root component)
64+
const sbomObj = typeof sbomContent === 'string' ? JSON.parse(sbomContent) : sbomContent;
65+
const rootRef = sbomObj?.metadata?.component?.["bom-ref"] || sbomObj?.metadata?.component?.purl;
66+
const purls = (sbomObj?.components || [])
67+
.map(c => c.purl || c["bom-ref"])
68+
.filter(Boolean)
69+
.filter(purl => !rootRef || purl !== rootRef);
70+
9571
if (purls.length === 0) {
9672
return {
97-
projectLicense: {
98-
manifest: manifestLicenseInfo,
99-
file: fileLicenseInfo,
100-
mismatch: finalMismatch
101-
},
73+
projectLicense: { manifest: manifestLicenseInfo, file: fileLicenseInfo, mismatch },
10274
incompatibleDependencies: []
10375
};
10476
}
10577

106-
// Get dependency licenses from analysis report (backend already provides this)
78+
// Get dependency licenses from analysis report
10779
const licenseByPurl = licenseMapFromAnalysisReport(analysisResult, purls);
10880
if (licenseByPurl.size === 0 && analysisResult) {
109-
// No license data in analysis report - this might be expected for some backends
11081
return {
111-
projectLicense: {
112-
manifest: manifestLicenseInfo,
113-
file: fileLicenseInfo,
114-
mismatch: finalMismatch
115-
},
82+
projectLicense: { manifest: manifestLicenseInfo, file: fileLicenseInfo, mismatch },
11683
incompatibleDependencies: [],
11784
error: 'No license data available in analysis report'
11885
};
11986
}
12087

121-
// Use backend category from project license details (prefer manifest, fallback to file)
122-
const projectCategory = manifestLicenseInfo?.category || fileLicenseInfo?.category || null;
88+
// Check compatibility for each dependency
89+
const projectCategory = manifestLicenseInfo?.category || fileLicenseInfo?.category;
12390
const incompatibleDependencies = [];
12491

12592
for (const purl of purls) {
126-
const entry = licenseByPurl.get(purl) || { licenses: [], category: undefined };
93+
const entry = licenseByPurl.get(purl);
94+
if (!entry) continue;
95+
12796
const status = getCompatibility(projectCategory, entry.category);
12897
if (status === 'incompatible') {
12998
incompatibleDependencies.push({
@@ -136,11 +105,7 @@ export async function runLicenseCheck(sbomContent, manifestPath, backendUrl, opt
136105
}
137106

138107
return {
139-
projectLicense: {
140-
manifest: manifestLicenseInfo,
141-
file: fileLicenseInfo,
142-
mismatch: finalMismatch
143-
},
108+
projectLicense: { manifest: manifestLicenseInfo, file: fileLicenseInfo, mismatch },
144109
incompatibleDependencies
145110
};
146111
}

0 commit comments

Comments
 (0)