FOSSology  4.7.1
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  case 'reuseBulk':
128  $reuseMode |= UploadDao::REUSE_BULK;
129  $reuserDependencies[] = 'agent_nomos';
130  $reuserDependencies[] = 'agent_monk';
131  $reuserDependencies[] = 'agent_ojo';
132  break;
133  }
134  }
135 
136  $reuseSelections = $request->get(self::UPLOAD_TO_REUSE_SELECTOR_NAME);
137  if (!is_array($reuseSelections)) {
138  $reuseSelections = [$reuseSelections];
139  }
140 
141  $reuseSelections = array_filter($reuseSelections, fn($s) => is_string($s) && substr_count($s, ',') >= 1);
142 
143  if (empty($reuseSelections)) {
144  $errorMsg .= 'No valid reuse upload selections found';
145  return -1;
146  }
147 
148  foreach ($reuseSelections as $reuseSelection) {
149  [$reuseUploadId, $reuseGroupId] = explode(',', $reuseSelection, 2);
150  $this->createPackageLink(
151  $uploadId,
152  intval($reuseUploadId),
153  intval($groupId),
154  intval($reuseGroupId),
155  $reuseMode
156  );
157  }
158 
159  list($agentDeps, $scancodeDeps) = $this->getReuserDependencies($request);
160  $reuserDependencies = array_unique(array_merge($reuserDependencies, $agentDeps));
161  if (!empty($scancodeDeps)) {
162  $reuserDependencies[] = $scancodeDeps;
163  }
164 
165  return $this->doAgentAdd($jobId, $uploadId, $errorMsg,
166  $reuserDependencies, $uploadId, null, $request);
167  }
168 
169  private function scheduleOsselotImportDirect(int $jobId, int $uploadId, string &$errorMsg, Request $request): int
170  {
171  $pkg = trim((string) $request->get('osselotPackage'));
172  $ver = trim((string) $request->get('osselotVersions'));
173  if (empty($pkg) || empty($ver)) {
174  $errorMsg .= 'Package name and version are required';
175  return -1;
176  }
177  try {
178  $helper = new OsselotLookupHelper();
179  $cachedPath = $helper->fetchSpdxFile($pkg, $ver);
180 
181  if (!$cachedPath || !is_file($cachedPath) || !is_readable($cachedPath)) {
182  throw new \RuntimeException("Could not fetch or read SPDX file for {$pkg}:{$ver}");
183  }
184 
185  global $SysConf;
186  $fileBase = $SysConf['FOSSOLOGY']['path'] . "/ReportImport/";
187 
188  if (!is_dir($fileBase) && !mkdir($fileBase, 0755, true)) {
189  throw new \RuntimeException('Failed to create ReportImport directory');
190  }
191 
192  $originalName = basename($cachedPath);
193  if (!str_ends_with($originalName, '.rdf.xml')) {
194  $baseName = pathinfo($originalName, PATHINFO_FILENAME);
195  $originalName = str_ends_with($originalName, '.rdf') ?
196  $baseName . '.rdf.xml' : $originalName . '.rdf.xml';
197  }
198 
199  $targetFile = time() . '_' . random_int(0, getrandmax()) . '_' . $originalName;
200  $targetPath = $fileBase . $targetFile;
201 
202  if (!copy($cachedPath, $targetPath)) {
203  throw new \RuntimeException('Failed to copy SPDX file');
204  }
205 
206  $reportImportAgent = plugin_find('agent_reportImport');
207  if (!$reportImportAgent || !method_exists($reportImportAgent, 'addReport') ||
208  !method_exists($reportImportAgent, 'setAdditionalJqCmdArgs') ||
209  !method_exists($reportImportAgent, 'AgentAdd')) {
210  throw new \RuntimeException('agent_reportImport plugin not available or missing methods');
211  }
212 
213  $importReq = new Request();
214 
215  $addNewLicensesAs = $request->get('osselotAddNewLicensesAs', 'candidate');
216  if (!in_array($addNewLicensesAs, ['candidate', 'approved', 'rejected'], true)) {
217  $addNewLicensesAs = 'candidate';
218  }
219  $importReq->request->set('addNewLicensesAs', $addNewLicensesAs);
220 
221  $booleanOptions = [
222  'addLicenseInfoFromInfoInFile', 'addLicenseInfoFromConcluded',
223  'addConcludedAsDecisions', 'addConcludedAsDecisionsOverwrite',
224  'addConcludedAsDecisionsTBD', 'addCopyrights'
225  ];
226 
227  foreach ($booleanOptions as $key) {
228  $fullKey = 'osselot' . ucfirst($key);
229  $rawValue = $request->get($fullKey);
230  $finalValue = $rawValue ? 'true' : 'false';
231  $importReq->request->set($key, $finalValue);
232  }
233 
234  $licenseMatch = $request->get('osselotLicenseMatch', 'spdxid');
235  if (!in_array($licenseMatch, ['spdxid', 'name', 'text'], true)) {
236  $licenseMatch = 'spdxid';
237  }
238  $importReq->request->set('licenseMatch', $licenseMatch);
239 
240  $jqCmdArgs = $reportImportAgent->addReport($targetFile);
241  $additionalArgs = $reportImportAgent->setAdditionalJqCmdArgs($importReq);
242  $jqCmdArgs .= $additionalArgs;
243 
244  $error = "";
245  $dependencies = array();
246  $jobQueueId = $reportImportAgent->AgentAdd($jobId, $uploadId, $error, $dependencies, $jqCmdArgs);
247 
248  if ($jobQueueId < 0) {
249  throw new \RuntimeException("Cannot schedule job: " . $error);
250  }
251 
252  return intval($jobQueueId);
253 
254  } catch (\Throwable $e) {
255  if (isset($targetPath) && file_exists($targetPath)) {
256  unlink($targetPath);
257  }
258  $errorMsg .= $e->getMessage();
259  error_log("OSSelot import error: " . $e->getMessage());
260  return -1;
261  }
262  }
263 
272  protected function createPackageLink($uploadId, $reuseUploadId, $groupId, $reuseGroupId, $reuseMode=0)
273  {
274  /* @var $packageDao PackageDao */
275  $packageDao = $GLOBALS['container']->get('dao.package');
276  $newUpload = $this->uploadDao->getUpload($uploadId);
277  $uploadForReuse = $this->uploadDao->getUpload($reuseUploadId);
278 
279  $package = $packageDao->findPackageForUpload($reuseUploadId);
280 
281  if ($package === null) {
282  $packageName = StringOperation::getCommonHead($uploadForReuse->getFilename(), $newUpload->getFilename());
283  $package = $packageDao->createPackage($packageName ?: $uploadForReuse->getFilename());
284  $packageDao->addUploadToPackage($reuseUploadId, $package);
285  }
286 
287  $packageDao->addUploadToPackage($uploadId, $package);
288 
289  $this->uploadDao->addReusedUpload($uploadId, $reuseUploadId, $groupId, $reuseGroupId, $reuseMode);
290  }
291 
297  private function getReuserDependencies($request)
298  {
299  $dependencies = array();
300  $scancodeDeps = [];
301  if ($request->get("Check_agent_nomos", false)) {
302  $dependencies[] = "agent_nomos";
303  }
304  if ($request->get("Check_agent_monk", false)) {
305  $dependencies[] = "agent_monk";
306  }
307  if ($request->get("Check_agent_ojo", false)) {
308  $dependencies[] = "agent_ojo";
309  }
310  if ($request->get("Check_agent_ninka", false)) {
311  $dependencies[] = "agent_ninka";
312  }
313  if ($request->get("Check_agent_copyright", false)) {
314  $dependencies[] = "agent_copyright";
315  }
316  if (!empty($request->get("scancodeFlags", []))) {
320  $agentScanCode = plugin_find('agent_scancode');
321  $flags = $request->get('scancodeFlags');
322  $unpackArgs = intval($request->get('scm', 0)) == 1 ? 'I' : '';
323  $scancodeDeps = [
324  "name" => "agent_scancode",
325  "args" => $agentScanCode->getScanCodeArgs($flags, $unpackArgs)
326  ];
327  }
328  return [$dependencies, $scancodeDeps];
329  }
330 }
331 
332 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