66 include_once(__DIR__ .
"/spdxutils.php");
68 include_once(__DIR__ .
"/version.php");
69 include_once(__DIR__ .
"/services.php");
162 function __construct()
165 $args = getopt(
"", array(self::OUTPUT_FORMAT_KEY.
'::'));
167 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
174 parent::__construct(
$agentName, AGENT_VERSION, AGENT_REV);
176 $this->uploadDao = $this->container->get(
'dao.upload');
177 $this->clearingDao = $this->container->get(
'dao.clearing');
178 $this->licenseDao = $this->container->get(
'dao.license');
179 $this->
dbManager = $this->container->get(
'db.manager');
180 $this->renderer = $this->container->get(
'twig.environment');
181 $this->renderer->setCache(
false);
183 $this->agentSpecifLongOptions[] = self::UPLOAD_ADDS.
':';
184 $this->agentSpecifLongOptions[] = self::OUTPUT_FORMAT_KEY.
':';
199 if ((!array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)
200 ||
$args[self::OUTPUT_FORMAT_KEY] ===
"")
201 && array_key_exists(self::UPLOAD_ADDS,
$args)) {
204 if (!array_key_exists(self::UPLOAD_ADDS,
$args) ||
$args[self::UPLOAD_ADDS] ===
"") {
219 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
220 $possibleOutputFormat =
trim(
$args[self::OUTPUT_FORMAT_KEY]);
221 if (in_array($possibleOutputFormat, explode(
',',self::AVAILABLE_OUTPUT_FORMATS))) {
222 $this->outputFormat = $possibleOutputFormat;
225 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, LicenseMap::REPORT,
true);
228 $docLicense = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
229 $docLicenseId = $docLicense->getId() .
"-" . md5($docLicense->getText());
231 ->setLicenseObj($docLicense)
232 ->setListedLicense(
true)
233 ->setCustomText(
false)
234 ->setTextPrinted(
true);
237 $additionalUploadIds = array_key_exists(self::UPLOAD_ADDS,
$args) ? explode(
',',
$args[self::UPLOAD_ADDS]) : array();
238 $packageIds = array($uploadId);
239 foreach ($additionalUploadIds as $additionalId) {
241 $packageIds[] = $additionalId;
244 $this->
writeReport($packageNodes, $packageIds, $uploadId);
255 $prefix = $this->outputFormat .
"-";
257 switch ($this->outputFormat) {
259 $postfix =
".xml" . $postfix;
265 $prefix .=
"copyright-";
270 $postfix =
".xml" . $postfix;
277 return $prefix . $partname . $postfix;
289 if ($this->filebasename ==
null) {
290 $fileName =
strtoupper($this->outputFormat).
"_".$packageName;
291 switch ($this->outputFormat) {
293 $fileName .=
".spdx.rdf";
296 $fileName .=
".spdx";
305 $fileName = $fileName .
".jsonld";
308 $fileName = $fileName .
".json";
311 $fileName = $fileName .
".spdx.rdf";
314 $fileName = $fileName .
".spdx";
317 $this->filebasename = $fileName;
330 $fileBase = $SysConf[
'FOSSOLOGY'][
'path'].
"/report/";
342 $url=$SysConf[
'SYSCONFIG'][
'FOSSologyURL'];
343 if (substr( $url, 0, 4 ) !==
"http") {
357 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
358 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
361 $filesWithLicenses = $this->reportutils
362 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
363 $this, $this->licensesInDocument);
366 $this->reportutils->addClearingStatus($filesWithLicenses,$itemTreeBounds, $this->groupId);
369 $scannerIDs = $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
370 $licenseComment =
"";
371 if (!empty($scannerIDs)) {
376 $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
379 $upload = $this->uploadDao->getUpload($uploadId);
380 $fileNodes = $this->
generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
382 $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
383 $mainLicenses = array();
384 foreach ($mainLicenseIds as $licId) {
385 $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
386 $mainLicense = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
387 $reportLicId = $mainLicense->getId() .
"-" . md5($mainLicense->getText());
388 $mainLicenses[] = $reportLicId;
389 if (!array_key_exists($reportLicId, $this->licensesInDocument)) {
390 $listedLicense = stripos($mainLicense->getSpdxId(),
391 LicenseRef::SPDXREF_PREFIX) !== 0;
393 ->setLicenseObj($mainLicense)
394 ->setCustomText(
false)
395 ->setListedLicense($listedLicense);
398 $mainLicenseString = [];
399 if ($this->outputFormat ==
"spdx2tv" ||
400 $this->outputFormat ==
"spdx2csv" ||
401 $this->outputFormat ==
"spdx3tv") {
402 foreach ($mainLicenses as $mainLicense) {
403 $shortName = $this->licensesInDocument[$mainLicense]
404 ->getLicenseObj()->getShortName();
406 LicenseRef::SPDXREF_PREFIX)) {
407 $mainLicenseString[] = $shortName;
409 $mainLicenseString[] = $this->licensesInDocument[$mainLicense]
410 ->getLicenseObj()->getSpdxId();
417 $hashes = $this->uploadDao->getUploadHashes($uploadId);
419 $reportInfo = $this->uploadDao->getReportInfo($uploadId);
420 $componentId = $reportInfo[
'ri_component_id'];
421 $componentType = $reportInfo[
'ri_component_type'];
422 $componentVersion = $reportInfo[
'ri_version'];
423 $generalAssessment = $reportInfo[
'ri_general_assesment'];
424 $releaseDate = $reportInfo[
'ri_release_date'];
425 if ($componentId ==
"NA") {
428 if ($componentVersion ==
"NA") {
429 $componentVersion =
"";
431 if ($generalAssessment ==
"NA") {
432 $generalAssessment =
"";
434 if ($releaseDate ==
"NA") {
437 $timeStamp = strtotime($releaseDate);
438 if ($timeStamp != -1) {
439 $releaseDate = date(
"Y-m-d\\T00:00:00\\Z", $timeStamp);
445 $componentType =
"maven-central";
447 $componentType =
"purl";
449 if (!empty($componentType)) {
458 'packageId' => $uploadId,
460 'packageName' => $upload->getFilename(),
461 'packageVersion' => $componentVersion,
462 'releaseDate' => $releaseDate,
463 'generalAssessment' => $generalAssessment,
464 'uploadName' => $upload->getFilename(),
465 'componentType' => $componentType,
466 'componentId' => htmlspecialchars($componentId),
467 'sha1' => $hashes[
'sha1'],
468 'md5' => $hashes[
'md5'],
469 'sha256' => $hashes[
'sha256'],
471 'mainLicenses' => $mainLicenses,
472 'mainLicenseString' => $mainLicenseString,
473 'licenseComments' => $licenseComment,
474 'fileNodes' => $fileNodes,
475 'obligations' => $obligations,
476 'licenseList' => $this->licensesInDocument
487 $func =
function($scannerId) use (
$agentDao)
489 return $agentDao->getAgentName($scannerId).
" (".
$agentDao->getAgentRev($scannerId).
")";
491 $scannerNames = array_map($func, $scannerIds);
492 return "licenseInfoInFile determined by Scanners:\n - ".implode(
"\n - ",$scannerNames);
505 if (!array_key_exists($licenses, $filesWithLicenses)) {
506 $filesWithLicenses[$licenses][
'files']=array();
507 $filesWithLicenses[$licenses][
'copyrights']=array();
509 if (empty($copyrights)) {
510 $copyrights = array();
512 $filesWithLicenses[$licenses][
'files'][$file] = $fullPath;
513 foreach ($copyrights as $copyright) {
514 if (!in_array($copyright, $filesWithLicenses[$licenses][
'copyrights'])) {
515 $filesWithLicenses[$licenses][
'copyrights'][] = $copyright;
528 $licensesWithFiles = array();
529 $treeDao = $this->container->get(
'dao.tree');
531 foreach ($filesWithLicenses as $fileId => $fileNode) {
532 $filesProceeded += 1;
533 if (($filesProceeded&2047)==0) {
536 $fullPath = $treeDao->getFullPath($fileId, $treeTableName, 0);
537 if (! empty($fileNode->getConcludedLicenses())) {
539 foreach ($fileNode->getConcludedLicenses() as $license) {
540 $licenses[] = $this->licensesInDocument[$license]
541 ->getLicenseObj()->getSpdxId();
546 $licenses, $fileNode->getCopyrights(), $fileId, $fullPath);
548 if (! empty($fileNode->getScanners())) {
549 $implodedLicenses = [];
550 foreach ($fileNode->getScanners() as $license) {
551 $implodedLicenses[] = $this->licensesInDocument[$license]
552 ->getLicenseObj()->getSpdxId();
556 if ($fileNode->isCleared()) {
557 $msgLicense =
"None (scanners found: " . $implodedLicenses .
")";
559 $msgLicense =
"NoLicenseConcluded (scanners found: " . $implodedLicenses .
")";
562 if ($fileNode->isCleared()) {
563 $msgLicense =
"None";
565 $msgLicense =
"NoLicenseConcluded";
569 $fileNode->getCopyrights(), $fileId, $fullPath);
572 return $licensesWithFiles;
581 $upload = $this->uploadDao->getUpload($uploadId);
582 $packageName = $upload->getFilename();
584 $this->uri = $this->
getUri($packageName);
585 $this->filename = $this->
getFileName($packageName);
594 protected function writeReport(&$packageNodes, $packageIds, $uploadId)
598 $fileBase = dirname($this->filename);
600 if (!is_dir($fileBase)) {
601 mkdir($fileBase, 0777,
true);
605 $organizationName = $SysConf[
'SYSCONFIG'][
"ReportHeaderText"] ??
'FOSSology';
606 $version = $SysConf[
'BUILD'][
'VERSION'];
608 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
609 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId,$uploadTreeTableName);
612 $filesWithLicenses = $this->reportutils
613 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
614 $this, $this->licensesInDocument);
616 $upload = $this->uploadDao->getUpload($uploadId);
617 $this->
generateFileNodes($filesWithLicenses, $upload->getTreeTableName(), $uploadId);
618 $this->declaredLicenseFileIds = array_unique(array_diff($this->declaredLicenseFileIds, $this->concludedLicenseFileIds));
619 $this->concludedLicenseFileIds = array_unique($this->concludedLicenseFileIds);
621 'documentName' => $fileBase,
623 'userName' => $this->container->get(
'dao.user')->getUserName($this->userId) .
" (" . $this->container->get(
'dao.user')->getUserEmail($this->userId) .
")",
624 'organisation' => $organizationName,
625 'concludedLicenseFileIds'=>$this->concludedLicenseFileIds,
626 'declaredLicenseFileIds'=>$this->declaredLicenseFileIds,
627 'toolVersion' =>
'fossology-' . $version,
628 'packageNodes' => $packageNodes,
629 'packageIds' => $packageIds,
630 'dataLicense' => $this->getSPDXDataLicense(),
631 'licenseList' => $this->licensesInDocument
637 $message = preg_replace(
'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/',
'?',$message);
639 file_put_contents($this->filename, $message);
651 $this->reportutils->updateOrInsertReportgenEntry($uploadId,
$jobId, $fileName);
662 return $this->renderer->load($templateName)->render($vars);
675 if (strcmp($this->outputFormat,
"dep5") !== 0) {
692 $treeDao = $this->container->get(
'dao.tree');
696 $textToBePrinted = [];
697 foreach ($filesWithLicenses as $fileId => $fileData) {
698 $filesProceeded += 1;
699 if (($filesProceeded & 2047) == 0) {
700 $this->
heartbeat($filesProceeded - $lastValue);
701 $lastValue = $filesProceeded;
703 $hashes = $treeDao->getItemHashes($fileId);
704 $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
707 foreach ($fileData->getConcludedLicenses() as $license) {
708 $this->concludedLicenseFileIds[] = $fileId;
709 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
710 $textToBePrinted[] = $license;
713 foreach ($fileData->getScanners() as $license) {
714 $this->declaredLicenseFileIds[] = $fileId;
715 if (! $this->licensesInDocument[$license]->isTextPrinted()) {
716 $textToBePrinted[] = $license;
719 $concludedLicensesString = [];
720 if ($this->outputFormat ==
"spdx2tv" ||
721 $this->outputFormat ==
"spdx2csv" ||
722 $this->outputFormat ==
"spdx3tv") {
723 foreach ($fileData->getConcludedLicenses() as $license) {
724 $shortName = $this->licensesInDocument[$license]
725 ->getLicenseObj()->getShortName();
727 LicenseRef::SPDXREF_PREFIX)) {
728 $concludedLicensesString[] = $shortName;
730 $concludedLicensesString[] = $this->licensesInDocument[$license]
731 ->getLicenseObj()->getSpdxId();
737 if (!$stateWoInfos ||
738 ($stateWoInfos && (!empty($fileData->getConcludedLicenses()) ||
739 !empty($fileData->getScanners()) || !empty($fileData->getCopyrights())))) {
740 $fileData->setAcknowledgements(
742 $fileData->setComments(
744 $dataTemplate = array(
746 'sha1' => $hashes[
'sha1'],
747 'md5' => $hashes[
'md5'],
748 'sha256' => $hashes[
'sha256'],
750 'fileName' => $fileName,
751 'fileDirName' => dirname($fileName),
752 'fileBaseName' => basename($fileName),
753 'fileData' => $fileData,
754 'licenseList' => $this->licensesInDocument,
755 'concludedLicensesString' => $concludedLicensesString,
756 'licenseCommentState' => $stateComment
761 foreach ($textToBePrinted as $license) {
762 $this->licensesInDocument[$license]->setTextPrinted(
true);
765 $this->
heartbeat($filesProceeded - $lastValue);
783 foreach ($licensesWithFiles as $licenseId=>$entry) {
784 $filesProceeded += count($entry[
'files']);
785 if ($filesProceeded&(~2047) > $lastStep) {
786 $this->
heartbeat($filesProceeded - $lastValue);
787 $lastStep = $filesProceeded&(~2047) + 2048;
788 $lastValue = $filesProceeded;
792 if (strrpos($licenseId,
"NoLicenseConcluded (scanners found: ", -strlen($licenseId)) !==
false) {
793 $comment = substr($licenseId,20,strlen($licenseId)-21);
794 $licenseId =
"NoLicenseConcluded";
795 } elseif (strrpos($licenseId,
"None (scanners found: ", -strlen($licenseId)) !==
false) {
796 $comment = substr($licenseId,6,strlen($licenseId)-7);
801 'fileNames'=>$entry[
'files'],
802 'license'=>$licenseId,
803 'copyrights'=>$entry[
'copyrights'],
804 'comment'=>$comment));
806 $this->
heartbeat($filesProceeded - $lastValue);
822 if ($upload->getTreeTableName()==
'uploadtree_a') {
823 $sql = $upload->getTreeTableName().
' WHERE upload_fk=$1 AND';
824 $param[] = $upload->getId();
826 $sql = $upload->getTreeTableName().
' WHERE';
827 $stmt .=
'.'.$upload->getTreeTableName();
830 $sql =
"SELECT STRING_AGG(lower_sha1,'') concat_sha1 FROM
831 (SELECT LOWER(pfile_sha1) lower_sha1 FROM pfile, $sql pfile_fk=pfile_pk AND parent IS NOT NULL ORDER BY pfile_sha1) templist";
832 $filelistPack = $this->
dbManager->getSingleRow($sql,$param,$stmt);
834 return sha1($filelistPack[
'concat_sha1']);
845 $sql =
"SELECT ri_spdx_selection FROM report_info WHERE upload_fk = $1";
846 $getCommentState = $this->
dbManager->getSingleRow($sql, array($uploadId), __METHOD__.
'.SPDX_license_comment');
847 if (!empty($getCommentState[
'ri_spdx_selection'])) {
848 $getCommentStateSingle = explode(
',', $getCommentState[
'ri_spdx_selection']);
849 if ($getCommentStateSingle[$key] ===
"checked") {
864 $licenses = $this->licenseClearedGetter->getCleared($uploadId, $this,
867 $licensesMain = $this->licenseMainGetter->getCleared($uploadId, $this,
870 list($obligations, $_) = $this->obligationsGetter->getObligations(
871 $licenses[
'statements'], $licensesMain[
'statements'], $uploadId,
873 if (empty($obligations)) {
876 return array_column($obligations,
"text");
886 $dataLic = $this->licenseDao->getLicenseByShortName(self::DATA_LICENSE);
887 return $dataLic->getId() .
"-" . md5($dataLic->getText());
903 $localList = array_values($this->licensesInDocument);
911 for ($i = 0; $i < count($localList) - 1; $i++) {
912 if ((! $localList[$i]->isCustomText() && ! $localList[$i + 1]->isCustomText()) &&
913 $localList[$i]->getLicenseObj()->getSpdxId() ===
914 $localList[$i + 1]->getLicenseObj()->getSpdxId()) {
915 $newShortName = $localList[$i + 1]->getLicenseObj()->getShortName();
917 $localList[$i + 1]->getLicenseObj()->getShortName(),
918 LicenseRef::SPDXREF_PREFIX)) {
919 $newShortName = LicenseRef::SPDXREF_PREFIX .
920 $localList[$i + 1]->getLicenseObj()->getShortName();
921 $newShortName = preg_replace(
'/\+$/',
'-or-later', $newShortName);
923 $md5 = md5($localList[$i + 1]->getLicenseObj()->getText());
924 $reportedLicenseShortname =
"$newShortName-$md5";
925 $licIndex = $localList[$i + 1]->getLicenseObj()->getId() .
"-$md5";
926 $oldLicObj = $this->licensesInDocument[$licIndex]->getLicenseObj();
927 $this->licensesInDocument[$licIndex]->setLicenseObj(
928 new License($oldLicObj->getId(), $reportedLicenseShortname,
929 $oldLicObj->getFullName(), $oldLicObj->getRisk(),
930 $oldLicObj->getText(), $oldLicObj->getUrl(),
931 $oldLicObj->getDetectorType(), $oldLicObj->getSpdxId()));
937 $agent =
new SpdxAgent();
938 $agent->scheduler_connect();
939 $agent->run_scheduler_event_loop();
940 $agent->scheduler_disconnect(0);
Structure of an Agent with all required parameters.
heartbeat($newProcessed)
Send hear beat to the scheduler.
Wrapper class for license map.
static stringStartsWith($haystack, $needle)
const DEFAULT_OUTPUT_FORMAT
Default output format.
getLicenseComment($scannerIds)
getFileName($packageName)
Get absolute path for report.
getVerificationCode(Upload $upload)
Get a unique identifier for a given upload.
getTemplateFile($partname)
Get TWIG template file based on output format.
const UPLOAD_ADDS
Argument for additional uploads.
getObligations(int $uploadId, int $groupId)
processUploadId($uploadId)
Given an upload ID, process the items in it.
const DATA_LICENSE
Data license for SPDX reports.
updateReportTable($uploadId, $jobId, $fileName)
Update the reportgen table with new report path.
preWorkOnArgs($args)
Parse arguments.
renderString($templateName, $vars)
Render a twig template.
const AVAILABLE_OUTPUT_FORMATS
Output formats available.
renderPackage($uploadId)
Given an upload id, render the report string.
getFileBasename($packageName)
Generate report basename based on upload name.
generateFileNodesByLicenses($filesWithLicenses, $treeTableName)
For each file, generate the nodes by licenses.
toLicensesWithFiles(&$filesWithLicenses, $treeTableName)
Map findings to the files.
generateFileNodes($filesWithLicenses, $treeTableName, $uploadId)
Generate report nodes for files.
getSPDXReportConf($uploadId, $key)
Get spdx license comment state for a given upload.
toLicensesWithFilesAdder(&$filesWithLicenses, $licenses, $copyrights, $file, $fullPath)
Map licenses, copyrights, files and full path to filesWithLicenses array.
generateFileNodesByFiles($filesWithLicenses, $treeTableName, $uploadId)
For each file, generate the nodes by files.
writeReport(&$packageNodes, $packageIds, $uploadId)
Write the report the file and update report table.
computeUri($uploadId)
For a given upload, compute the URI and filename for the report.
const OUTPUT_FORMAT_KEY
Argument key for output format.
getUri($packageName)
Get the URI for the given package.
deduplicateLicenseList()
De-duplicate license list by comparing licenses with the same SPDX ID.
static preWorkOnArgsFlp($args, $key1, $key2)
For a given set of arguments assign $args[$key1] and $args[$key2].
static implodeLicenses($licenses)
Implode licenses with "AND" or "OR".
static removeEmptyLicenses($licenses)
static cleanTextArray($texts)
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 SPDX2 agent.
list_t type structure used to keep various lists. (e.g. there are multiple lists).