35 include_once(__DIR__ .
"/version.php");
36 include_once(__DIR__ .
"/reportgenerator.php");
46 const UPLOADS_ADD_KEY =
"uploadsAdd";
51 private $additionalUploads = [];
103 private $packageName;
105 function __construct()
108 $args = getopt(
"", array(
109 self::OUTPUT_FORMAT_KEY.
'::',
110 self::UPLOADS_ADD_KEY.
'::'
113 if (array_key_exists(self::OUTPUT_FORMAT_KEY,
$args)) {
119 if (array_key_exists(self::UPLOADS_ADD_KEY,
$args)) {
120 $uploadsString =
$args[self::UPLOADS_ADD_KEY];
121 if (!empty($uploadsString)) {
122 $this->additionalUploads = explode(
',', $uploadsString);
126 parent::__construct(
$agentName, AGENT_VERSION, AGENT_REV);
128 $this->uploadDao = $this->container->get(
'dao.upload');
129 $this->clearingDao = $this->container->get(
'dao.clearing');
130 $this->licenseDao = $this->container->get(
'dao.license');
131 $this->
dbManager = $this->container->get(
'db.manager');
143 $this->licenseMap =
new LicenseMap($this->
dbManager, $this->groupId, LicenseMap::REPORT,
true);
160 if (count($this->additionalUploads) > 0) {
161 $fileName = $fileBase .
"multifile" .
"_" .
strtoupper($this->outputFormat);
163 $fileName = $fileBase.
strtoupper($this->outputFormat).
"_".$this->packageName;
166 return $fileName .
".json" ;
176 $upload = $this->uploadDao->getUpload($uploadId);
177 $this->packageName = $upload->getFilename();
179 $fileBase = $SysConf[
'FOSSOLOGY'][
'path'].
"/report/";
181 $this->uri = $this->
getUri($fileBase);
192 $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
193 $itemTreeBounds = $this->uploadDao->getParentItemBounds($uploadId, $uploadTreeTableName);
196 $filesWithLicenses = $this->reportutils
197 ->getFilesWithLicensesFromClearings($itemTreeBounds, $this->groupId,
198 $this, $this->licensesInDocument);
201 $this->reportutils->addClearingStatus($filesWithLicenses, $itemTreeBounds, $this->groupId);
204 $this->reportutils->addScannerResults($filesWithLicenses, $itemTreeBounds, $this->groupId, $this->licensesInDocument);
207 $this->reportutils->addCopyrightResults($filesWithLicenses, $uploadId);
210 $customLicenseTexts = $this->clearingDao->getMainLicenseReportInfos($uploadId, $this->groupId);
212 $upload = $this->uploadDao->getUpload($uploadId);
213 $components = $this->
generateFileComponents($filesWithLicenses, $upload->getTreeTableName(), $uploadId, $itemTreeBounds, $customLicenseTexts);
215 $mainLicenseIds = $this->clearingDao->getMainLicenseIds($uploadId, $this->groupId);
216 $mainLicenses = array();
217 $seenLicenseIds = array();
218 foreach ($mainLicenseIds as $licId) {
219 $reportedLicenseId = $this->licenseMap->getProjectedId($licId);
220 $mainLicObj = $this->licenseDao->getLicenseById($reportedLicenseId, $this->groupId);
221 if ($mainLicObj ===
null) {
226 $mainLicenses[] = $this->reportGenerator->createLicense($licensedata);
228 $customText = array_key_exists($licId, $customLicenseTexts) ? $customLicenseTexts[$licId] :
null;
229 $licText = !empty($customText) ? $customText : $mainLicObj->getText();
230 $reportLicId = $mainLicObj->getId() .
"-" . md5($licText);
231 $seenLicenseIds[$reportLicId] =
true;
234 foreach ($filesWithLicenses as $fileNode) {
235 $licenseIds = !empty($fileNode->getConcludedLicenses())
236 ? $fileNode->getConcludedLicenses()
237 : $fileNode->getScanners();
238 foreach ($licenseIds as $licenseId) {
239 if (array_key_exists($licenseId, $this->licensesInDocument) && !array_key_exists($licenseId, $seenLicenseIds)) {
240 $seenLicenseIds[$licenseId] =
true;
241 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
242 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
244 $mainLicenses[] = $this->reportGenerator->createLicense($licensedata);
249 $hashes = $this->uploadDao->getUploadHashes($uploadId);
250 $serializedhash = array();
251 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-1', $hashes[
'sha1']);
252 $serializedhash[] = $this->reportGenerator->createHash(
'MD5', $hashes[
'md5']);
254 if (array_key_exists(
'sha256', $hashes) && !empty($hashes[
'sha256'])) {
255 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-256', $hashes[
'sha256']);
258 $allCopyrights = array();
259 foreach ($filesWithLicenses as $fileNode) {
260 $fileCopyrights = $fileNode->getCopyrights();
261 if (!empty($fileCopyrights)) {
262 $allCopyrights = array_merge($allCopyrights, $fileCopyrights);
265 $allCopyrights = array_unique($allCopyrights);
267 $reportInfo = $this->uploadDao->getReportInfo($uploadId);
268 $componentVersion = ($reportInfo[
'ri_version'] ??
'');
269 if ($componentVersion ==
'NA') {
270 $componentVersion =
'';
272 $componentId = ($reportInfo[
'ri_component_id'] ??
'');
273 if ($componentId ==
'NA') {
276 $componentType = intval($reportInfo[
'ri_component_type'] ?? 0);
277 $generalAssessment = ($reportInfo[
'ri_general_assesment'] ??
'');
278 if ($generalAssessment ==
'NA') {
279 $generalAssessment =
'';
283 $externalReferences = [];
284 if (!empty($componentId)) {
286 $purl = $componentId;
288 $externalReferences[] = [
289 'type' =>
'distribution',
290 'url' => $componentId
295 $maincomponentData = array (
296 'bomref' => strval($uploadId),
298 'name' => $upload->getFilename(),
299 'version' => $componentVersion,
300 'hashes' => $serializedhash,
301 'scope' =>
'required',
302 'mimeType' => $this->getMimeType($uploadId),
303 'copyright' => implode(
"\n", $allCopyrights),
304 'description' => $generalAssessment,
306 'externalReferences' => $externalReferences,
307 'licenses' => $mainLicenses
309 $maincomponent = $this->reportGenerator->createComponent($maincomponentData);
312 'tool-version' => $SysConf[
'BUILD'][
'VERSION'],
313 'maincomponent' => $maincomponent,
314 'components' => $components,
315 'externalReferences' => $externalReferences
318 return $this->reportGenerator->generateReport($bomdata);
328 protected function generateFileComponents($filesWithLicenses, $treeTableName, $uploadId, $itemTreeBounds, $customLicenseTexts = array())
331 $treeDao = $this->container->get(
'dao.tree');
335 $components = array();
336 foreach ($filesWithLicenses as $fileId => $licenses) {
337 $filesProceeded += 1;
338 if (($filesProceeded & 2047) == 0) {
339 $this->
heartbeat($filesProceeded - $lastValue);
340 $lastValue = $filesProceeded;
343 $hashes = $treeDao->getItemHashes($fileId);
344 $serializedhash = array();
345 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-1', $hashes[
'sha1']);
346 $serializedhash[] = $this->reportGenerator->createHash(
'MD5', $hashes[
'md5']);
348 if (array_key_exists(
'sha256', $hashes) && !empty($hashes[
'sha256'])) {
349 $serializedhash[] = $this->reportGenerator->createHash(
'SHA-256', $hashes[
'sha256']);
352 $fileName = $treeDao->getFullPath($fileId, $treeTableName, 0);
355 if (!empty($licenses->getConcludedLicenses())) {
356 foreach ($licenses->getConcludedLicenses() as $licenseId) {
357 if (array_key_exists($licenseId, $this->licensesInDocument)) {
358 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
359 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
361 $licensesfound[] = $this->reportGenerator->createLicense($licensedata);
365 foreach ($licenses->getScanners() as $licenseId) {
366 if (array_key_exists($licenseId, $this->licensesInDocument)) {
367 $licObj = $this->licensesInDocument[$licenseId]->getLicenseObj();
368 $isCustomText = $this->licensesInDocument[$licenseId]->isCustomText();
370 $licensesfound[] = $this->reportGenerator->createLicense($licensedata);
374 if (!empty($fileName)) {
376 $componentdata = array(
377 'bomref' => $uploadId .
'-'. $fileId,
380 'hashes' => $serializedhash,
381 'mimeType' => $mimeType,
382 'copyright' => implode(
"\n", $licenses->getCopyrights()),
383 'licenses' => $licensesfound,
384 'acknowledgements' => implode(
"\n", $licenses->getAcknowledgements()),
385 'comments' => implode(
"\n", $licenses->getComments())
387 $components[] = $this->reportGenerator->createComponent($componentdata);
390 $this->
heartbeat($filesProceeded - $lastValue);
401 $fileBase = dirname($this->uri);
403 if (!is_dir($fileBase)) {
404 mkdir($fileBase, 0777,
true);
408 $contents = json_encode($packageNodes, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
411 $contents = preg_replace(
'/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u',
'?',$contents);
412 file_put_contents($this->uri, $contents);
424 $this->reportutils->updateOrInsertReportgenEntry($uploadId,
$jobId, $fileName);
438 $customText = array_key_exists($licenseId, $customLicenseTexts) ? $customLicenseTexts[$licenseId] :
null;
439 $licText = !empty($customText) ? $customText : $licObj->getText();
441 $licensedata = array(
442 'url' => $licObj->getUrl()
445 if (!empty($customText) || $isCustomText) {
446 if (!empty($customText)) {
447 $prefix = \Fossology\Lib\Data\LicenseRef::SPDXREF_PREFIX;
448 $licensedata[
'name'] = $prefix . $licObj->getShortName() .
'-' . md5($customText);
450 $licensedata[
'name'] = $licObj->getShortName();
453 $spdxId = $licObj->getSpdxId();
454 if (!empty($spdxId)) {
455 $licensedata[
'id'] = $spdxId;
457 $licensedata[
'name'] = $licObj->getFullName();
461 if ($includeText && !empty($licText)) {
462 $licensedata[
'textContent'] = base64_encode($licText);
463 $licensedata[
'textContentType'] =
'text/plain';
475 $sql =
"SELECT mimetype_name
477 JOIN pfile pf ON u.pfile_fk = pf.pfile_pk
478 JOIN mimetype m ON pf.pfile_mimetypefk = m.mimetype_pk
479 WHERE u.upload_pk = $1";
481 $row = $this->
dbManager->getSingleRow($sql, [$uploadId], __METHOD__);
482 return $row[
'mimetype_name'];
493 $sql =
"SELECT m.mimetype_name
494 FROM $treeTableName ut
495 JOIN pfile pf ON ut.pfile_fk = pf.pfile_pk
496 LEFT JOIN mimetype m ON pf.pfile_mimetypefk = m.mimetype_pk
497 WHERE ut.uploadtree_pk = $1";
499 $row = $this->
dbManager->getSingleRow($sql, [$fileId], __METHOD__);
500 return $row[
'mimetype_name'] ??
'application/octet-stream';
504 $agent =
new CycloneDXAgent();
505 $agent->scheduler_connect();
506 $agent->run_scheduler_event_loop();
507 $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.
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.