FOSSology  4.6.0
Open Source License Compliance by Open Source Software
agent-reuser.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2014-2018 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
14 namespace Fossology\Reuser;
15 
23 use Symfony\Component\HttpFoundation\Request;
24 
25 include_once(dirname(__DIR__) . "/agent/version.php");
26 
32 {
33  const UPLOAD_TO_REUSE_SELECTOR_NAME = 'uploadToReuse';
34  const REUSE_MODE = 'reuseMode';
35 
39  private $uploadDao;
40 
41  public function __construct()
42  {
43  $this->Name = "agent_reuser";
44  $this->Title = _("Reuse of License Clearing");
45  $this->AgentName = "reuser";
46 
47  parent::__construct();
48 
49  $this->uploadDao = $GLOBALS['container']->get('dao.upload');
50  }
51 
57  public function renderContent(&$vars)
58  {
59  $reuserPlugin = plugin_find('plugin_reuser');
60  return $reuserPlugin->renderContent($vars);
61  }
62 
68  public function renderFoot(&$vars)
69  {
70  $reuserPlugin = plugin_find('plugin_reuser');
71  return $reuserPlugin->renderFoot($vars);
72  }
73 
79  public function getScriptIncludes(&$vars)
80  {
81  $reuserPlugin = plugin_find('plugin_reuser');
82  return $reuserPlugin->getScriptIncludes($vars);
83  }
84 
89  public function preInstall()
90  {
91  menu_insert("ParmAgents::" . $this->Title, 0, $this->Name);
92  }
93 
102  public function scheduleAgent($jobId, $uploadId, &$errorMsg, $request)
103  {
104  if ($request->get('reuseSource') === 'osselot') {
105  return $this->scheduleOsselotImportDirect($jobId, $uploadId, $errorMsg, $request);
106  }
107 
108  $groupId = $request->get('groupId', Auth::getGroupId());
109  $getReuseValue = $request->get(self::REUSE_MODE) ?: array();
110  $reuserDependencies = array("agent_adj2nest");
111 
112  $reuseMode = UploadDao::REUSE_NONE;
113  foreach ($getReuseValue as $currentReuseValue) {
114  switch ($currentReuseValue) {
115  case 'reuseMain':
116  $reuseMode |= UploadDao::REUSE_MAIN;
117  break;
118  case 'reuseEnhanced':
119  $reuseMode |= UploadDao::REUSE_ENHANCED;
120  break;
121  case 'reuseConf':
122  $reuseMode |= UploadDao::REUSE_CONF;
123  break;
124  case 'reuseCopyright':
125  $reuseMode |= UploadDao::REUSE_COPYRIGHT;
126  break;
127  }
128  }
129 
130  $reuseSelections = $request->get(self::UPLOAD_TO_REUSE_SELECTOR_NAME);
131  if (!is_array($reuseSelections)) {
132  $reuseSelections = [$reuseSelections];
133  }
134 
135  $reuseSelections = array_filter($reuseSelections, fn($s) => is_string($s) && substr_count($s, ',') >= 1);
136 
137  if (empty($reuseSelections)) {
138  $errorMsg .= 'No valid reuse upload selections found';
139  return -1;
140  }
141 
142  foreach ($reuseSelections as $reuseSelection) {
143  [$reuseUploadId, $reuseGroupId] = explode(',', $reuseSelection, 2);
144  $this->createPackageLink(
145  $uploadId,
146  intval($reuseUploadId),
147  intval($groupId),
148  intval($reuseGroupId),
149  $reuseMode
150  );
151  }
152 
153  list($agentDeps, $scancodeDeps) = $this->getReuserDependencies($request);
154  $reuserDependencies = array_unique(array_merge($reuserDependencies, $agentDeps));
155  if (!empty($scancodeDeps)) {
156  $reuserDependencies[] = $scancodeDeps;
157  }
158 
159  return $this->doAgentAdd($jobId, $uploadId, $errorMsg,
160  $reuserDependencies, $uploadId, null, $request);
161  }
162 
163  private function scheduleOsselotImportDirect(int $jobId, int $uploadId, string &$errorMsg, Request $request): int
164  {
165  $pkg = trim((string) $request->get('osselotPackage'));
166  $ver = trim((string) $request->get('osselotVersions'));
167  if (empty($pkg) || empty($ver)) {
168  $errorMsg .= 'Package name and version are required';
169  return -1;
170  }
171  try {
172  $helper = new OsselotLookupHelper();
173  $cachedPath = $helper->fetchSpdxFile($pkg, $ver);
174 
175  if (!$cachedPath || !is_file($cachedPath) || !is_readable($cachedPath)) {
176  throw new \RuntimeException("Could not fetch or read SPDX file for {$pkg}:{$ver}");
177  }
178 
179  global $SysConf;
180  $fileBase = $SysConf['FOSSOLOGY']['path'] . "/ReportImport/";
181 
182  if (!is_dir($fileBase) && !mkdir($fileBase, 0755, true)) {
183  throw new \RuntimeException('Failed to create ReportImport directory');
184  }
185 
186  $originalName = basename($cachedPath);
187  if (!str_ends_with($originalName, '.rdf.xml')) {
188  $baseName = pathinfo($originalName, PATHINFO_FILENAME);
189  $originalName = str_ends_with($originalName, '.rdf') ?
190  $baseName . '.rdf.xml' : $originalName . '.rdf.xml';
191  }
192 
193  $targetFile = time() . '_' . random_int(0, getrandmax()) . '_' . $originalName;
194  $targetPath = $fileBase . $targetFile;
195 
196  if (!copy($cachedPath, $targetPath)) {
197  throw new \RuntimeException('Failed to copy SPDX file');
198  }
199 
200  $reportImportAgent = plugin_find('agent_reportImport');
201  if (!$reportImportAgent || !method_exists($reportImportAgent, 'addReport') ||
202  !method_exists($reportImportAgent, 'setAdditionalJqCmdArgs') ||
203  !method_exists($reportImportAgent, 'AgentAdd')) {
204  throw new \RuntimeException('agent_reportImport plugin not available or missing methods');
205  }
206 
207  $importReq = new Request();
208 
209  $addNewLicensesAs = $request->get('osselotAddNewLicensesAs', 'candidate');
210  if (!in_array($addNewLicensesAs, ['candidate', 'approved', 'rejected'], true)) {
211  $addNewLicensesAs = 'candidate';
212  }
213  $importReq->request->set('addNewLicensesAs', $addNewLicensesAs);
214 
215  $booleanOptions = [
216  'addLicenseInfoFromInfoInFile', 'addLicenseInfoFromConcluded',
217  'addConcludedAsDecisions', 'addConcludedAsDecisionsOverwrite',
218  'addConcludedAsDecisionsTBD', 'addCopyrights'
219  ];
220 
221  foreach ($booleanOptions as $key) {
222  $fullKey = 'osselot' . ucfirst($key);
223  $rawValue = $request->get($fullKey);
224  $finalValue = $rawValue ? 'true' : 'false';
225  $importReq->request->set($key, $finalValue);
226  }
227 
228  $licenseMatch = $request->get('osselotLicenseMatch', 'spdxid');
229  if (!in_array($licenseMatch, ['spdxid', 'name', 'text'], true)) {
230  $licenseMatch = 'spdxid';
231  }
232  $importReq->request->set('licenseMatch', $licenseMatch);
233 
234  $jqCmdArgs = $reportImportAgent->addReport($targetFile);
235  $additionalArgs = $reportImportAgent->setAdditionalJqCmdArgs($importReq);
236  $jqCmdArgs .= $additionalArgs;
237 
238  $error = "";
239  $dependencies = array();
240  $jobQueueId = $reportImportAgent->AgentAdd($jobId, $uploadId, $error, $dependencies, $jqCmdArgs);
241 
242  if ($jobQueueId < 0) {
243  throw new \RuntimeException("Cannot schedule job: " . $error);
244  }
245 
246  return intval($jobQueueId);
247 
248  } catch (\Throwable $e) {
249  if (isset($targetPath) && file_exists($targetPath)) {
250  unlink($targetPath);
251  }
252  $errorMsg .= $e->getMessage();
253  error_log("OSSelot import error: " . $e->getMessage());
254  return -1;
255  }
256  }
257 
266  protected function createPackageLink($uploadId, $reuseUploadId, $groupId, $reuseGroupId, $reuseMode=0)
267  {
268  /* @var $packageDao PackageDao */
269  $packageDao = $GLOBALS['container']->get('dao.package');
270  $newUpload = $this->uploadDao->getUpload($uploadId);
271  $uploadForReuse = $this->uploadDao->getUpload($reuseUploadId);
272 
273  $package = $packageDao->findPackageForUpload($reuseUploadId);
274 
275  if ($package === null) {
276  $packageName = StringOperation::getCommonHead($uploadForReuse->getFilename(), $newUpload->getFilename());
277  $package = $packageDao->createPackage($packageName ?: $uploadForReuse->getFilename());
278  $packageDao->addUploadToPackage($reuseUploadId, $package);
279  }
280 
281  $packageDao->addUploadToPackage($uploadId, $package);
282 
283  $this->uploadDao->addReusedUpload($uploadId, $reuseUploadId, $groupId, $reuseGroupId, $reuseMode);
284  }
285 
291  private function getReuserDependencies($request)
292  {
293  $dependencies = array();
294  $scancodeDeps = [];
295  if ($request->get("Check_agent_nomos", false)) {
296  $dependencies[] = "agent_nomos";
297  }
298  if ($request->get("Check_agent_monk", false)) {
299  $dependencies[] = "agent_monk";
300  }
301  if ($request->get("Check_agent_ojo", false)) {
302  $dependencies[] = "agent_ojo";
303  }
304  if ($request->get("Check_agent_ninka", false)) {
305  $dependencies[] = "agent_ninka";
306  }
307  if ($request->get("Check_agent_copyright", false)) {
308  $dependencies[] = "agent_copyright";
309  }
310  if (!empty($request->get("scancodeFlags", []))) {
314  $agentScanCode = plugin_find('agent_scancode');
315  $flags = $request->get('scancodeFlags');
316  $unpackArgs = intval($request->get('scm', 0)) == 1 ? 'I' : '';
317  $scancodeDeps = [
318  "name" => "agent_scancode",
319  "args" => $agentScanCode->getScanCodeArgs($flags, $unpackArgs)
320  ];
321  }
322  return [$dependencies, $scancodeDeps];
323  }
324 }
325 
326 register_plugin(new ReuserAgentPlugin());
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
static getGroupId()
Get the current user's group id.
Definition: Auth.php:80
doAgentAdd($jobId, $uploadId, &$errorMsg, $dependencies, $jqargs="", $jq_cmd_args=null, $request=null)
UI element for reuser during Uploading new package.
scheduleAgent($jobId, $uploadId, &$errorMsg, $request)
Get parameters from request and add to job queue.
renderContent(&$vars)
Render twig templates for plugin_reuser.
const REUSE_MODE
Form element name for main license to reuse.
const UPLOAD_TO_REUSE_SELECTOR_NAME
Form element name for main license to reuse.
createPackageLink($uploadId, $reuseUploadId, $groupId, $reuseGroupId, $reuseMode=0)
Create links between old and new upload.
getScriptIncludes(&$vars)
Get script tags to include before rendering foot.
renderFoot(&$vars)
Render footer twig templates for plugin_reuser.
menu_insert($Path, $LastOrder=0, $URI=NULL, $Title=NULL, $Target=NULL, $HTML=NULL)
Given a Path, order level for the last item, and optional plugin name, insert the menu item.
plugin_find($pluginName)
Given the official name of a plugin, return the $Plugins object.
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690