35 include_once(__DIR__ .
"/version.php");
36 include_once(__DIR__ .
"/reportgenerator.php");
46 const UPLOADS_ADD_KEY =
"uploadsAdd";
51 private $additionalUploads = [];
60 protected $citations = [];
107 private $packageName;
109 function __construct()
112 $args = getopt(
"", array(
113 self::OUTPUT_FORMAT_KEY.
'::',
114 self::UPLOADS_ADD_KEY.
'::'
117 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
123 if (array_key_exists(self::UPLOADS_ADD_KEY,
$args)) {
124 $uploadsString =
$args[self::UPLOADS_ADD_KEY];
125 if (!empty($uploadsString)) {
126 $this->additionalUploads = explode(
',', $uploadsString);
130 parent::__construct(
$agentName, AGENT_VERSION, AGENT_REV);
132 $this->uploadDao = $this->container->get(
'dao.upload');
133 $this->clearingDao = $this->container->get(
'dao.clearing');
134 $this->licenseDao = $this->container->get(
'dao.license');
135 $this->
dbManager = $this->container->get(
'db.manager');
147 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, LicenseMap::REPORT,
true);
164 if (count($this->additionalUploads) > 0) {
165 $fileName = $fileBase .
"multifile" .
"_" .
strtoupper($this->outputFormat);
167 $fileName = $fileBase.
strtoupper($this->outputFormat).
"_".$this->packageName;
170 return $fileName .
".json" ;
180 $upload = $this->uploadDao->getUpload($uploadId);
181 $this->packageName = $upload->getFilename();
183 $fileBase = $SysConf[
'FOSSOLOGY'][
'path'].
"/report/";
185 $this->uri = $this->
getUri($fileBase);
196 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
197 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId, $uploadTreeTableName);
200 $filesWithLicenses = $this->reportutils
201 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
202 $this, $this->licensesInDocument);
205 $this->reportutils->addClearingStatus($filesWithLicenses, $itemTreeBounds, $this->groupId);
208 $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
211 $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
216 'timestamp' => date(
'c'),
217 'attributedTo' =>
'tool-fossology-scanners',
221 'timestamp' => date(
'c'),
222 'attributedTo' =>
'person-fossology-analyst',
227 $customLicenseTexts = $this->clearingDao->getMainLicenseReportInfos($uploadId, $this->groupId);
229 $upload = $this->uploadDao->getUpload($uploadId);
230 $components = $this->
generateFileComponents($filesWithLicenses, $upload->getTreeTableName(), $uploadId, $itemTreeBounds, $customLicenseTexts);
232 $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
233 $mainLicenses = array();
234 $seenLicenseIds = array();
235 foreach ($mainLicenseIds as $licId) {
236 $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
237 $mainLicObj = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
238 if ($mainLicObj ===
null) {
243 $licensedata[
'bom-ref'] =
'lic-clearing-main-' . $licId;
244 $licensedata[
'acknowledgement'] =
'concluded';
245 $this->citations[
'cite-analyst'][
'expressions'][] =
'$..[?(@.bom-ref=="lic-clearing-main-' . $licId .
'")]';
246 $mainLicenses[] = $this->reportGenerator->createLicense($licensedata);
248 $customText = array_key_exists($licId, $customLicenseTexts) ? $customLicenseTexts[$licId] :
null;
249 $licText = !empty($customText) ? $customText : $mainLicObj->getText();
250 $reportLicId = $mainLicObj->getId() .
"-" . md5($licText);
251 $seenLicenseIds[$reportLicId] =
true;
254 foreach ($filesWithLicenses as $fileNode) {
255 $isConcluded = !empty($fileNode->getConcludedLicenses());
256 $licenseIds = $isConcluded
257 ? $fileNode->getConcludedLicenses()
258 : $fileNode->getScanners();
259 foreach ($licenseIds as $licenseId) {
260 if (array_key_exists($licenseId, $this->licensesInDocument) && !array_key_exists($licenseId, $seenLicenseIds)) {
261 $seenLicenseIds[$licenseId] =
true;
262 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
263 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
265 $refPrefix = $isConcluded ?
'clearing' :
'scanner';
266 $licensedata[
'bom-ref'] =
'lic-' . $refPrefix .
'-main-' . $licenseId;
267 $licensedata[
'acknowledgement'] = $isConcluded ?
'concluded' :
'declared';
268 $this->citations[
'cite-' . ($isConcluded ?
'analyst' :
'scanner')][
'expressions'][] =
'$..[?(@.bom-ref=="lic-' . $refPrefix .
'-main-' . $licenseId .
'")]';
269 $mainLicenses[] = $this->reportGenerator->createLicense($licensedata);
274 $hashes = $this->uploadDao->getUploadHashes($uploadId);
275 $serializedhash = array();
276 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-1', $hashes[
'sha1']);
277 $serializedhash[] = $this->reportGenerator->createHash(
'MD5', $hashes[
'md5']);
279 if (array_key_exists(
'sha256', $hashes) && !empty($hashes[
'sha256'])) {
280 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-256', $hashes[
'sha256']);
283 $allCopyrights = array();
284 foreach ($filesWithLicenses as $fileNode) {
285 $fileCopyrights = $fileNode->getCopyrights();
286 if (!empty($fileCopyrights)) {
287 $allCopyrights = array_merge($allCopyrights, $fileCopyrights);
290 $allCopyrights = array_unique($allCopyrights);
292 $reportInfo = $this->uploadDao->getReportInfo($uploadId);
293 $componentVersion = ($reportInfo[
'ri_version'] ??
'');
294 if ($componentVersion ==
'NA') {
295 $componentVersion =
'';
297 $componentId = ($reportInfo[
'ri_component_id'] ??
'');
298 if ($componentId ==
'NA') {
301 $componentType = intval($reportInfo[
'ri_component_type'] ?? 0);
302 $generalAssessment = ($reportInfo[
'ri_general_assesment'] ??
'');
303 if ($generalAssessment ==
'NA') {
304 $generalAssessment =
'';
308 $externalReferences = [];
309 if (!empty($componentId)) {
311 $purl = $componentId;
313 $externalReferences[] = [
314 'type' =>
'distribution',
315 'url' => $componentId
320 $maincomponentData = array (
321 'bomref' => strval($uploadId),
323 'name' => $upload->getFilename(),
324 'version' => $componentVersion,
325 'hashes' => $serializedhash,
326 'scope' =>
'required',
327 'mimeType' => $this->getMimeType($uploadId),
328 'copyright' => implode(
"\n", $allCopyrights),
329 'description' => $generalAssessment,
331 'externalReferences' => $externalReferences,
332 'licenses' => $mainLicenses
334 $maincomponent = $this->reportGenerator->createComponent($maincomponentData);
336 $formattedDate = date(
'Y-m-d\TH:i:s\Z');
338 $finalCitations = [];
339 if (!empty($this->citations[
'cite-scanner'][
'expressions'])) {
340 $finalCitations[] = $this->citations[
'cite-scanner'];
342 if (!empty($this->citations[
'cite-analyst'][
'expressions'])) {
343 $finalCitations[] = $this->citations[
'cite-analyst'];
347 'timestamp' => $formattedDate,
348 'tool-version' => $SysConf[
'BUILD'][
'VERSION'],
349 'maincomponent' => $maincomponent,
350 'components' => $components,
351 'externalReferences' => $externalReferences,
352 'citations' => $finalCitations
355 return $this->reportGenerator->generateReport($bomdata);
365 protected function generateFileComponents($filesWithLicenses, $treeTableName, $uploadId, $itemTreeBounds, $customLicenseTexts = array())
368 $treeDao = $this->container->get(
'dao.tree');
374 $components = array();
375 foreach ($filesWithLicenses as $fileId => $licenses) {
376 $filesProceeded += 1;
377 if (($filesProceeded & 2047) == 0) {
378 $this->
heartbeat($filesProceeded - $lastValue);
379 $lastValue = $filesProceeded;
382 if ($stateWoInfos && empty($licenses->getConcludedLicenses()) &&
383 empty($licenses->getScanners()) && empty($licenses->getCopyrights())) {
387 $hashes = $treeDao->getItemHashes($fileId);
388 $serializedhash = array();
389 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-1', $hashes[
'sha1']);
390 $serializedhash[] = $this->reportGenerator->createHash(
'MD5', $hashes[
'md5']);
392 if (array_key_exists(
'sha256', $hashes) && !empty($hashes[
'sha256'])) {
393 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-256', $hashes[
'sha256']);
396 $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
399 if (!empty($licenses->getConcludedLicenses())) {
400 foreach ($licenses->getConcludedLicenses() as $licenseId) {
401 if (array_key_exists($licenseId, $this->licensesInDocument)) {
402 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
403 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
405 $licensedata[
'bom-ref'] =
'lic-clearing-' . $licenseId .
'-' . $fileId;
406 $licensedata[
'acknowledgement'] =
'concluded';
407 $licensesfound[] = $this->reportGenerator->createLicense($licensedata,
false);
411 foreach ($licenses->getScanners() as $licenseId) {
412 if (array_key_exists($licenseId, $this->licensesInDocument)) {
413 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
414 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
416 $licensedata[
'bom-ref'] =
'lic-scanner-' . $licenseId .
'-' . $fileId;
417 $licensedata[
'acknowledgement'] =
'declared';
418 $licensesfound[] = $this->reportGenerator->createLicense($licensedata,
false);
422 if (!empty($fileName)) {
424 $componentdata = array(
425 'bomref' => $uploadId .
'-'. $fileId,
428 'hashes' => $serializedhash,
429 'mimeType' => $mimeType,
430 'copyright' => implode(
"\n", $licenses->getCopyrights()),
431 'licenses' => $licensesfound,
432 'acknowledgements' => implode(
"\n", $licenses->getAcknowledgements()),
433 'comments' => implode(
"\n", $licenses->getComments())
435 $components[] = $this->reportGenerator->createComponent($componentdata);
438 $this->
heartbeat($filesProceeded - $lastValue);
449 $fileBase = dirname($this->uri);
451 if (!is_dir($fileBase)) {
452 mkdir($fileBase, 0777,
true);
456 $contents = json_encode($packageNodes, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
459 $contents = preg_replace(
'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u',
'?',$contents);
460 file_put_contents($this->uri, $contents);
472 $this->reportutils->updateOrInsertReportgenEntry($uploadId,
$jobId, $fileName);
486 $customText = array_key_exists($licenseId, $customLicenseTexts) ? $customLicenseTexts[$licenseId] :
null;
487 $licText = !empty($customText) ? $customText : $licObj->getText();
489 $licensedata = array(
490 'url' => $licObj->getUrl()
493 if (!empty($customText) || $isCustomText) {
494 if (!empty($customText)) {
495 $prefix = \Fossology\Lib\Data\LicenseRef::SPDXREF_PREFIX;
496 $licensedata[
'name'] = $prefix . $licObj->getShortName() .
'-' . md5($customText);
498 $licensedata[
'name'] = $licObj->getShortName();
501 $spdxId = $licObj->getSpdxId();
502 if (!empty($spdxId)) {
503 $licensedata[
'id'] = $spdxId;
505 $licensedata[
'name'] = $licObj->getFullName();
509 if ($includeText && !empty($licText)) {
510 $licensedata[
'textContent'] = base64_encode($licText);
511 $licensedata[
'textContentType'] =
'text/plain';
523 $sql =
"SELECT mimetype_name
525 JOIN pfile pf ON u.pfile_fk = pf.pfile_pk
526 JOIN mimetype m ON pf.pfile_mimetypefk = m.mimetype_pk
527 WHERE u.upload_pk = $1";
529 $row = $this->
dbManager->getSingleRow($sql, [$uploadId], __METHOD__);
530 return $row[
'mimetype_name'];
541 $sql =
"SELECT m.mimetype_name
542 FROM $treeTableName ut
543 JOIN pfile pf ON ut.pfile_fk = pf.pfile_pk
544 LEFT JOIN mimetype m ON pf.pfile_mimetypefk = m.mimetype_pk
545 WHERE ut.uploadtree_pk = $1";
547 $row = $this->
dbManager->getSingleRow($sql, [$fileId], __METHOD__);
548 return $row[
'mimetype_name'] ??
'application/octet-stream';
561 $settings = $this->uploadDao->getCyclonedxSettings($uploadId);
562 if (!empty($settings)) {
563 $settingsArr = explode(
',', $settings);
564 if (isset($settingsArr[$key]) && $settingsArr[$key] ===
"checked") {
572 $agent =
new CycloneDXAgent();
573 $agent->scheduler_connect();
574 $agent->run_scheduler_event_loop();
575 $agent->scheduler_disconnect(0);
const OUTPUT_FORMAT_KEY
Argument key for output format.
getFileMimeType($fileId, $treeTableName)
Get the mime type of a file.
writeReport($packageNodes, $uploadId)
Write the report the file and update report table.
updateReportTable($uploadId, $jobId, $fileName)
Update the reportgen table with new report path.
renderPackage($uploadId)
Given an upload id, render the report string.
getCycloneDXReportConf($uploadId, $key)
Get CycloneDX report conf state for a given upload.
getMimeType($uploadId)
Get the mime type of the upload.
processUploadId($uploadId)
Given an upload ID, process the items in it.
getUri($fileBase)
Get the URI for the given package.
const DEFAULT_OUTPUT_FORMAT
Default output format.
computeUri($uploadId)
For a given upload, compute the URI.
getLicenseDataForCycloneDX($licObj, $licenseId, $customLicenseTexts, $isCustomText=false, $includeText=true)
Helper to create license data array taking custom text into account.
generateFileComponents($filesWithLicenses, $treeTableName, $uploadId, $itemTreeBounds, $customLicenseTexts=array())
Generate the components by files.
Structure of an Agent with all required parameters.
heartbeat($newProcessed)
Send hear beat to the scheduler.
Wrapper class for license map.
char * trim(char *ptext)
Trimming whitespace.
int jobId
The id of the job.
fo_dbManager * dbManager
fo_dbManager object
FUNCTION char * strtoupper(char *s)
Helper function to upper case a string.
Namespace used by CycloneDX agent.