FOSSology  4.7.0-rc1
Open Source License Compliance by Open Source Software
DeciderAgent.php
Go to the documentation of this file.
1 <?php
2 /*
3  Author: Daniele Fognini
4  SPDX-FileCopyrightText: © 2014-2019 Siemens AG
5  SPDX-FileCopyrightText: © 2021 Orange by Piotr Pszczola <piotr.pszczola@orange.com>
6  SPDX-FileCopyrightText: © 2021 Kaushlendra Pratap <kaushlendrapratap.9837@gmail.com>
7 
8  SPDX-License-Identifier: GPL-2.0-only
9 */
49 namespace Fossology\Decider;
50 
69 use Symfony\Component\Process\Process;
70 
71 include_once(__DIR__ . "/version.php");
72 
77 class DeciderAgent extends Agent
78 {
79  const RULES_NOMOS_IN_MONK = 0x1;
80  const RULES_NOMOS_MONK_NINKA = 0x2;
81  const RULES_BULK_REUSE = 0x4;
82  const RULES_WIP_SCANNER_UPDATES = 0x8;
83  const RULES_OJO_NO_CONTRADICTION = 0x10;
84  const RULES_COPYRIGHT_FALSE_POSITIVE = 0x20;
85  const RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER = 0x40;
86  const RULES_LICENSE_TYPE_CONCLUSION = 0x80;
87  const RULES_ALL = self::RULES_NOMOS_IN_MONK | self::RULES_NOMOS_MONK_NINKA |
88  self::RULES_BULK_REUSE | self::RULES_WIP_SCANNER_UPDATES |
89  self::RULES_OJO_NO_CONTRADICTION | self::RULES_LICENSE_TYPE_CONCLUSION;
90 
94  private $activeRules;
98  private $licenseType;
102  private $uploadDao;
114  private $clearingDao;
118  private $highlightDao;
122  private $showJobsDao;
126  private $decisionTypes;
130  private $licenseMap = null;
134  private $licenseMapUsage = null;
135 
139  private $copyrightDao;
140 
145 
149  private $licenseDao;
150 
151  function __construct($licenseMapUsage=null)
152  {
153  parent::__construct(AGENT_DECIDER_NAME, AGENT_DECIDER_VERSION, AGENT_DECIDER_REV);
154 
155  $this->uploadDao = $this->container->get('dao.upload');
156  $this->clearingDao = $this->container->get('dao.clearing');
157  $this->highlightDao = $this->container->get('dao.highlight');
158  $this->showJobsDao = $this->container->get('dao.show_jobs');
159  $this->decisionTypes = $this->container->get('decision.types');
160  $this->clearingDecisionProcessor = $this->container->get('businessrules.clearing_decision_processor');
161  $this->agentLicenseEventProcessor = $this->container->get('businessrules.agent_license_event_processor');
162  $this->copyrightDao = $this->container->get('dao.copyright');
163  $this->compatibilityDao = $this->container->get('dao.compatibility');
164  $this->licenseDao = $this->container->get('dao.license');
165  $this->licenseMapUsage = $licenseMapUsage;
166  $this->agentSpecifOptions = "r:t:";
167  }
168 
173  function processUploadId($uploadId)
174  {
175  $args = $this->args;
176  $this->activeRules = array_key_exists('r', $args) ? intval($args['r']) : self::RULES_ALL;
177  $this->licenseType = array_key_exists('t', $args) ?
178  $this->getLicenseType(str_replace(["'", '"'], "", $args['t'])) : "";
179  $this->licenseMap = new LicenseMap($this->dbManager, $this->groupId, $this->licenseMapUsage);
180 
181  if (array_key_exists("r", $args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE)== self::RULES_COPYRIGHT_FALSE_POSITIVE)) {
182  $this->getCopyrightsToDisableFalsePositivesClutter($uploadId, false);
183  }
184  if (array_key_exists("r", $args) && (($this->activeRules&self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)== self::RULES_COPYRIGHT_FALSE_POSITIVE_CLUTTER)) {
185  $this->getCopyrightsToDisableFalsePositivesClutter($uploadId, true);
186  }
187  if (array_key_exists("r", $args) && (($this->activeRules&self::RULES_BULK_REUSE)== self::RULES_BULK_REUSE)) {
188  $bulkReuser = new BulkReuser();
189  $bulkIds = $this->clearingDao->getPreviousBulkIds($uploadId, $this->groupId, $this->userId);
190  if (count($bulkIds) == 0) {
191  return true;
192  }
193  $jqId=0;
194  $minTime="4";
195  $maxTime="60";
196  foreach ($bulkIds as $bulkId) {
197  $jqId = $bulkReuser->rerunBulkAndDeciderOnUpload($uploadId, $this->groupId, $this->userId, $bulkId, $jqId);
198  $this->heartbeat(1);
199  if (!empty($jqId)) {
200  $jqIdRow = $this->showJobsDao->getDataForASingleJob($jqId);
201  while ($this->showJobsDao->getJobStatus($jqId)) {
202  $this->heartbeat(0);
203  $timeInSec = $this->showJobsDao->getEstimatedTime($jqIdRow['jq_job_fk'],'',0,0,1);
204  if ($timeInSec > $maxTime) {
205  sleep($maxTime);
206  } else if ($timeInSec < $minTime) {
207  sleep($minTime);
208  } else {
209  sleep($timeInSec);
210  }
211  }
212  }
213  }
214  }
215  $parentBounds = $this->uploadDao->getParentItemBounds($uploadId);
216  foreach ($this->uploadDao->getContainedItems($parentBounds) as $item) {
217  $process = $this->processItem($item);
218  $this->heartbeat($process);
219  }
220  return true;
221  }
222 
232  private function processItem(Item $item)
233  {
234  $itemTreeBounds = $item->getItemTreeBounds();
235 
236  $unMappedMatches = $this->agentLicenseEventProcessor->getLatestScannerDetectedMatches($itemTreeBounds);
237  $projectedScannerMatches = $this->remapByProjectedId($unMappedMatches);
238 
239  $lastDecision = $this->clearingDao->getRelevantClearingDecision($itemTreeBounds, $this->groupId);
240 
241  if (null!==$lastDecision && $lastDecision->getType()==DecisionTypes::IRRELEVANT) {
242  return 0;
243  }
244 
245  $currentEvents = $this->clearingDao->getRelevantClearingEvents($itemTreeBounds, $this->groupId);
246 
247  $markAsWip = false;
248  if (null !== $lastDecision && $projectedScannerMatches
249  && ($this->activeRules & self::RULES_WIP_SCANNER_UPDATES) == self::RULES_WIP_SCANNER_UPDATES) {
250  $licensesFromDecision = array();
251  foreach ($lastDecision->getClearingLicenses() as $clearingLicense) {
252  $licenseIdFromEvent = $this->licenseMap->getProjectedId($clearingLicense->getLicenseId());
253  $licensesFromDecision[$licenseIdFromEvent] = $licenseIdFromEvent;
254  }
255  $markAsWip = $this->existsUnhandledMatch($projectedScannerMatches,$licensesFromDecision);
256  }
257 
258  if (null !== $lastDecision && $markAsWip) {
259  $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
260  return 1;
261  }
262 
263  if (null!==$lastDecision || 0<count($currentEvents)) {
264  return 0;
265  }
266 
267  $haveDecided = false;
268 
269  if (($this->activeRules&self::RULES_OJO_NO_CONTRADICTION) == self::RULES_OJO_NO_CONTRADICTION) {
270  $haveDecided = $this->autodecideIfOjoMatchesNoContradiction($itemTreeBounds, $projectedScannerMatches);
271  }
272 
273  if (!$haveDecided && ($this->activeRules&self::RULES_OJO_NO_CONTRADICTION) == self::RULES_OJO_NO_CONTRADICTION) {
274  $haveDecided = $this->autodecideIfResoMatchesNoContradiction($itemTreeBounds, $projectedScannerMatches);
275  }
276 
277  if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_IN_MONK) == self::RULES_NOMOS_IN_MONK) {
278  $haveDecided = $this->autodecideNomosMatchesInsideMonk($itemTreeBounds, $projectedScannerMatches);
279  }
280 
281  if (!$haveDecided && ($this->activeRules&self::RULES_NOMOS_MONK_NINKA)== self::RULES_NOMOS_MONK_NINKA) {
282  $haveDecided = $this->autodecideNomosMonkNinka($itemTreeBounds, $projectedScannerMatches);
283  }
284 
285  if (!$haveDecided && ($this->activeRules &
286  self::RULES_LICENSE_TYPE_CONCLUSION) ==
287  self::RULES_LICENSE_TYPE_CONCLUSION) {
288  $haveDecided = $this->autodecideLicenseType($itemTreeBounds,
289  $projectedScannerMatches);
290  }
291 
292  if (!$haveDecided && $markAsWip) {
293  $this->clearingDao->markDecisionAsWip($item->getId(), $this->userId, $this->groupId);
294  }
295 
296  return ($haveDecided||$markAsWip ? 1 : 0);
297  }
298 
305  private function existsUnhandledMatch($projectedScannerMatches, $licensesFromDecision)
306  {
307  foreach (array_keys($projectedScannerMatches) as $projectedLicenseId) {
308  if (!array_key_exists($projectedLicenseId, $licensesFromDecision)) {
309  return true;
310  }
311  }
312  return false;
313  }
314 
323  private function autodecideIfOjoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
324  {
325  $licenseMatchExists = count($matches) > 0;
326  foreach ($matches as $licenseMatches) {
327  $licenseMatchExists = $licenseMatchExists && $this->areOtherScannerFindingsAndOJOAgreed($licenseMatches);
328  }
329 
330  if ($licenseMatchExists) {
331  try {
332  $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
333  $itemTreeBounds, $this->userId, $this->groupId,
334  DecisionTypes::IDENTIFIED, false);
335  } catch (\Exception $e) {
336  echo "Can not auto decide as file '" .
337  $itemTreeBounds->getItemId() . "' contains candidate license.\n";
338  }
339  }
340  return $licenseMatchExists;
341  }
342 
351  private function autodecideIfResoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
352  {
353  $licenseMatchExists = count($matches) > 0;
354  foreach ($matches as $licenseMatches) {
355  $licenseMatchExists = $licenseMatchExists && $this->areOtherScannerFindingsAndRESOAgreed($licenseMatches);
356  }
357 
358  if ($licenseMatchExists) {
359  try {
360  $this->clearingDecisionProcessor->makeDecisionFromLastEvents(
361  $itemTreeBounds, $this->userId, $this->groupId,
362  DecisionTypes::IDENTIFIED, false);
363  } catch (\Exception $e) {
364  echo "Can not auto decide as file '" .
365  $itemTreeBounds->getItemId() . "' contains candidate license.\n";
366  }
367  }
368  return $licenseMatchExists;
369  }
370 
379  private function autodecideNomosMonkNinka(ItemTreeBounds $itemTreeBounds, $matches)
380  {
381  $canDecide = (count($matches)>0);
382 
383  foreach ($matches as $licenseMatches) {
384  if (!$canDecide) { // &= is not lazy
385  break;
386  }
387  $canDecide &= $this->areNomosMonkNinkaAgreed($licenseMatches);
388  }
389 
390  if ($canDecide) {
391  $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=true);
392  }
393  return $canDecide;
394  }
395 
404  private function autodecideNomosMatchesInsideMonk(ItemTreeBounds $itemTreeBounds, $matches)
405  {
406  $canDecide = (count($matches)>0);
407 
408  foreach ($matches as $licenseMatches) {
409  if (!$canDecide) { // &= is not lazy
410  break;
411  }
412  $canDecide &= $this->areNomosMatchesInsideAMonkMatch($licenseMatches);
413  }
414 
415  if ($canDecide) {
416  $this->clearingDecisionProcessor->makeDecisionFromLastEvents($itemTreeBounds, $this->userId, $this->groupId, DecisionTypes::IDENTIFIED, $global=true);
417  }
418  return $canDecide;
419  }
420 
430  private function autodecideLicenseType(ItemTreeBounds $itemTreeBounds,
431  $matches)
432  {
433  $canDecide = $this->noLicenseConflict($itemTreeBounds, $matches);
434  if ($canDecide) {
435  $canDecide &= $this->allLicenseInType($matches);
436  }
437 
438  if ($canDecide) {
439  $this->clearingDecisionProcessor
440  ->makeDecisionFromLastEvents($itemTreeBounds, $this->userId,
441  $this->groupId, DecisionTypes::IDENTIFIED, DecisionScopes::ITEM, [], true);
442  }
443  return $canDecide;
444  }
445 
452  protected function remapByProjectedId($matches)
453  {
454  $remapped = array();
455  foreach ($matches as $licenseId => $licenseMatches) {
456  $projectedId = $this->licenseMap->getProjectedId($licenseId);
457 
458  foreach ($licenseMatches as $agent => $agentMatches) {
459  $haveId = array_key_exists($projectedId, $remapped);
460  $haveAgent = $haveId && array_key_exists($agent, $remapped[$projectedId]);
461  if ($haveAgent) {
462  $remapped[$projectedId][$agent] = array_merge($remapped[$projectedId][$agent], $agentMatches);
463  } else {
464  $remapped[$projectedId][$agent] = $agentMatches;
465  }
466  }
467  }
468  return $remapped;
469  }
470 
477  private function isRegionIncluded($small, $big)
478  {
479  return ($big[0] >= 0) && ($small[0] >= $big[0]) && ($small[1] <= $big[1]);
480  }
481 
487  private function areNomosMatchesInsideAMonkMatch($licenseMatches)
488  {
489  if (!array_key_exists("nomos", $licenseMatches)) {
490  return false;
491  }
492  if (!array_key_exists("monk", $licenseMatches)) {
493  return false;
494  }
495 
496  foreach ($licenseMatches["nomos"] as $licenseMatch) {
497  $matchId = $licenseMatch->getLicenseFileId();
498  $nomosRegion = $this->highlightDao->getHighlightRegion($matchId);
499 
500  $found = false;
501  foreach ($licenseMatches["monk"] as $monkLicenseMatch) {
502  $monkRegion = $this->highlightDao->getHighlightRegion($monkLicenseMatch->getLicenseFileId());
503  if ($this->isRegionIncluded($nomosRegion, $monkRegion)) {
504  $found = true;
505  break;
506  }
507  }
508  if (!$found) {
509  return false;
510  }
511  }
512 
513  return true;
514  }
515 
521  protected function areNomosMonkNinkaAgreed($licenseMatches)
522  {
523  $scanners = array('nomos','monk','ninka');
524  $vote = array();
525  foreach ($scanners as $scanner) {
526  if (!array_key_exists($scanner, $licenseMatches)) {
527  return false;
528  }
529  foreach ($licenseMatches[$scanner] as $licenseMatch) {
530  $licId = $licenseMatch->getLicenseId();
531  $vote[$licId][$scanner] = true;
532  }
533  }
534 
535  foreach ($vote as $licId=>$voters) {
536  if (count($voters) != 3) {
537  return false;
538  }
539  }
540  return true;
541  }
542 
549  protected function getLicenseIdsOfMatchesForScanner($scanner, $licenseMatches)
550  {
551  if (array_key_exists($scanner, $licenseMatches) === true) {
552  return array_map(
553  function ($match) {
554  return $match->getLicenseId();
555  }, $licenseMatches[$scanner]);
556  }
557  return [];
558  }
559 
565  protected function areOtherScannerFindingsAndOJOAgreed($licenseMatches)
566  {
567  $findingsByOjo = $this->getLicenseIdsOfMatchesForScanner('ojo', $licenseMatches);
568  if (count($findingsByOjo) == 0) {
569  // nothing to do
570  return false;
571  }
572 
573  $findingsByOtherScanner = $this->getLicenseIdsOfMatchesForScanner('nomos', $licenseMatches);
574  if (count($findingsByOtherScanner) == 0) {
575  // nothing found by other scanner, so no contradiction
576  return true;
577  }
578  foreach ($findingsByOtherScanner as $findingsByScanner) {
579  if (in_array($findingsByScanner, $findingsByOjo) === false) {
580  // contradiction found
581  return false;
582  }
583  }
584  return true;
585  }
586 
592  protected function areOtherScannerFindingsAndRESOAgreed($licenseMatches)
593  {
594  $findingsByReso = $this->getLicenseIdsOfMatchesForScanner('reso', $licenseMatches);
595  if (count($findingsByReso) == 0) {
596  // nothing to do
597  return false;
598  }
599 
600  $findingsByOtherScanner = $this->getLicenseIdsOfMatchesForScanner('nomos', $licenseMatches);
601  if (count($findingsByOtherScanner) == 0) {
602  // nothing found by other scanner, so no contradiction
603  return true;
604  }
605  foreach ($findingsByOtherScanner as $findingsByScanner) {
606  if (in_array($findingsByScanner, $findingsByReso) === false) {
607  // contradiction found
608  return false;
609  }
610  }
611  return true;
612  }
613 
621  $clutter_flag): void
622  {
623  if (empty($uploadId)) {
624  return;
625  }
626  $agentName = 'copyright';
627  $uploadTreeTableName = $this->uploadDao->getUploadtreeTableName($uploadId);
628  $scanJobProxy = new ScanJobProxy($GLOBALS['container']->get('dao.agent'), $uploadId);
629  $scanJobProxy->createAgentStatus(array($agentName));
630  $selectedScanners = $scanJobProxy->getLatestSuccessfulAgentIds();
631  if (!array_key_exists($agentName, $selectedScanners)) {
632  return;
633  }
634  $latestXpAgentId = $selectedScanners[$agentName];
635  $extrawhere = ' agent_fk='.$latestXpAgentId;
636  $allCopyrights = $this->copyrightDao->getScannerEntries('copyright',
637  $uploadTreeTableName, $uploadId, null, $extrawhere);
638 
639  if (empty($allCopyrights)) {
640  echo "No copyrights found for upload $uploadId. Skipping false positive deactivation.\n";
641  return;
642  }
643 
644  $copyrightJSON = json_encode($allCopyrights);
645  $tmpFile = tmpfile();
646  $tmpFilePath = stream_get_meta_data($tmpFile)['uri'];
647  fwrite($tmpFile, $copyrightJSON);
648  $deactivatedCopyrightData = $this->callCopyrightDeactivationClutterRemovalScript($tmpFilePath, $clutter_flag);
649  if (empty($deactivatedCopyrightData)) {
650  fclose($tmpFile);
651  return;
652  }
653  $deactivatedCopyrights = json_decode($deactivatedCopyrightData, true);
654  foreach ($deactivatedCopyrights as $deactivatedCopyright) {
655  $item = $deactivatedCopyright['uploadtree_pk'];
656  $itemTreeBounds = $this->uploadDao->getItemTreeBounds($item, $uploadTreeTableName);
657  $hash = $deactivatedCopyright['hash'];
658  $content = $deactivatedCopyright['content'];
659  $cpTable = 'copyright';
660  if ($deactivatedCopyright['is_copyright'] == "t") {
661  $action = '';
662  if (array_key_exists('decluttered_content', $deactivatedCopyright) &&
663  !empty($deactivatedCopyright['decluttered_content'])) {
664  $content = $deactivatedCopyright['decluttered_content'];
665  } else {
666  // No text update. Nothing to do.
667  $this->heartbeat(1);
668  continue;
669  }
670  } else {
671  $action = 'delete';
672  }
673  $this->copyrightDao->updateTable($itemTreeBounds, $hash, $content, $this->userId, $cpTable, $action);
674  $this->heartbeat(1);
675  }
676  fclose($tmpFile);
677  }
678 
685  private function callCopyrightDeactivationClutterRemovalScript($tmpFilePath,
686  $clutter_flag): string
687  {
688  $script = "copyrightDeactivationClutterRemovalScript.py";
689  $args = ["python3", __DIR__ . "/$script", "--file", $tmpFilePath];
690  if ($clutter_flag) {
691  $args[] = "--clutter";
692  }
693 
694  $sleepTime = 5;
695  $maxSleepTime = 25;
696 
697  $process = new Process($args);
698  $process->setTimeout(null); // Remove timeout to run indefinitely.
699  $process->setEnv(set_python_path());
700  $process->start();
701 
702  do {
703  $this->heartbeat(0);
704  sleep($sleepTime);
705  if ($sleepTime < $maxSleepTime) {
706  $sleepTime += 5;
707  }
708  } while ($process->isRunning());
709 
710  echo $process->getErrorOutput();
711 
712  return $process->getOutput();
713  }
714 
720  private function getLicenseType($licenseType)
721  {
722  global $SysConf;
723  $licenseTypes = array_map('trim', explode(',',
724  $SysConf['SYSCONFIG']['LicenseTypes']));
725  if (in_array($licenseType, $licenseTypes)) {
726  return $licenseType;
727  }
728  return "";
729  }
730 
738  protected function noLicenseConflict($itemTreeBounds, $licenseMatches)
739  {
740  $shortnames = [];
741  foreach ($licenseMatches as $agentMatch) {
742  foreach ($agentMatch as $agentLicenseMatches) {
743  foreach ($agentLicenseMatches as $licenseMatch) {
744  $shortnames[$licenseMatch->getLicenseId()] = $licenseMatch
745  ->getLicenseRef()->getShortName();
746  }
747  }
748  }
749  foreach ($shortnames as $shortname) {
750  try {
751  if (! $this->compatibilityDao->getCompatibilityForFile($itemTreeBounds,
752  $shortname)) {
753  return false;
754  }
755  } catch (InvalidAgentStageException $_) {
756  return false;
757  }
758  }
759  return true;
760  }
761 
767  protected function allLicenseInType($licenseMatches)
768  {
769  $licenseTypes = [];
770  foreach ($licenseMatches as $agentMatch) {
771  foreach ($agentMatch as $agentLicenseMatches) {
772  foreach ($agentLicenseMatches as $licenseMatch) {
773  if (!array_key_exists($licenseMatch->getLicenseId(), $licenseTypes)) {
774  $licenseTypes[$licenseMatch->getLicenseId()] = $this->licenseDao
775  ->getLicenseType($licenseMatch->getLicenseId());
776  }
777  }
778  }
779  }
780  if (! in_array($this->licenseType, $licenseTypes)) {
781  return false;
782  }
783  if (! empty(array_diff($licenseTypes, [$this->licenseType]))) {
784  return false;
785  }
786  return true;
787  }
788 }
Prepares bulk licenses for an upload and run DeciderJob on it.
Definition: BulkReuser.php:23
Agent to decide license findings in an upload.
existsUnhandledMatch($projectedScannerMatches, $licensesFromDecision)
Check if matches contains unhandled match.
areOtherScannerFindingsAndRESOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
autodecideIfResoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk, OJO and Reso findings.
processItem(Item $item)
Given an item, check with the $activeRules and apply rules to it.
areOtherScannerFindingsAndOJOAgreed($licenseMatches)
Check if the finding by only contains one single license and that no other scanner (nomos) has produc...
callCopyrightDeactivationClutterRemovalScript($tmpFilePath, $clutter_flag)
autodecideNomosMatchesInsideMonk(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches by nomos which are in monk findings.
noLicenseConflict($itemTreeBounds, $licenseMatches)
Check if findings by all agents are same or not.
autodecideNomosMonkNinka(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and ninka findings.
processUploadId($uploadId)
Given an upload ID, process the items in it.
allLicenseInType($licenseMatches)
Check if findings by all agents are same or not.
autodecideLicenseType(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches where there is no license conflict.
getLicenseIdsOfMatchesForScanner($scanner, $licenseMatches)
extracts the matches corresponding to a scanner from a $licenseMatches structure
isRegionIncluded($small, $big)
Check if the small highlight region is inside big one.
autodecideIfOjoMatchesNoContradiction(ItemTreeBounds $itemTreeBounds, $matches)
Auto decide matches which are in nomos, monk and OJO findings.
areNomosMatchesInsideAMonkMatch($licenseMatches)
Check if matches by nomos are inside monk findings.
getCopyrightsToDisableFalsePositivesClutter($uploadId, $clutter_flag)
remapByProjectedId($matches)
Given a set of matches, remap according to project id instead of license id.
areNomosMonkNinkaAgreed($licenseMatches)
Check if findings by all agents are same or not.
Structure of an Agent with all required parameters.
Definition: Agent.php:41
heartbeat($newProcessed)
Send hear beat to the scheduler.
Definition: Agent.php:203
Utility functions to process ClearingDecision.
Wrapper class for license map.
Definition: LicenseMap.php:19
set_python_path()
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
Namespace for decider agent.
Definition: BulkReuser.php:8
$GLOBALS['xyyzzzDeciderJob']