"Fossies" - the Fresh Open Source Software Archive

Member "cli-1.1280.1/src/lib/ecosystems/resolve-test-facts.ts" (20 Feb 2024, 10329 Bytes) of package /linux/misc/snyk-cli-1.1280.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 import { AuthFailedError } from '../errors';
    2 import { Options, PolicyOptions } from '../types';
    3 import { spinner } from '../../lib/spinner';
    4 import {
    5   Ecosystem,
    6   ScanResult,
    7   TestResult,
    8   FileSignaturesDetails,
    9 } from './types';
   10 import {
   11   CreateDepGraphResponse,
   12   GetIssuesResponse,
   13   FileHashes,
   14   Attributes,
   15 } from './unmanaged/types';
   16 import {
   17   requestTestPollingToken,
   18   pollingTestWithTokenUntilDone,
   19   createDepGraph,
   20   getDepGraph,
   21   getIssues,
   22 } from '../polling/polling-test';
   23 import { extractAndApplyPluginAnalytics } from './plugin-analytics';
   24 import { findAndLoadPolicy } from '../policy';
   25 import { filterIgnoredIssues } from './policy';
   26 import { IssueDataUnmanaged, Issue } from '../snyk-test/legacy';
   27 import {
   28   convertDepGraph,
   29   convertMapCasing,
   30   convertToCamelCase,
   31   getOrg,
   32 } from './unmanaged/utils';
   33 import { sleep } from '../common';
   34 import { SEVERITY } from '../snyk-test/common';
   35 
   36 export async function resolveAndTestFacts(
   37   ecosystem: Ecosystem,
   38   scans: {
   39     [dir: string]: ScanResult[];
   40   },
   41   options: Options & PolicyOptions,
   42 ): Promise<[TestResult[], string[]]> {
   43   try {
   44     return await resolveAndTestFactsUnmanagedDeps(scans, options);
   45   } catch (error) {
   46     const unauthorized = error.code === 401 || error.code === 403;
   47 
   48     if (unauthorized) {
   49       throw AuthFailedError(
   50         'Unauthorized request to unmanaged service',
   51         error.code,
   52       );
   53     }
   54 
   55     throw error;
   56   }
   57 }
   58 
   59 export async function submitHashes(
   60   hashes: FileHashes,
   61   orgId: string,
   62 ): Promise<string> {
   63   const response: CreateDepGraphResponse = await createDepGraph(hashes, orgId);
   64 
   65   return response.data.id;
   66 }
   67 
   68 export async function pollDepGraphAttributes(
   69   id: string,
   70   orgId: string,
   71 ): Promise<Attributes> {
   72   const minIntervalMs = 2000;
   73   const maxIntervalMs = 20000;
   74 
   75   let totalElaspedTime = 0;
   76   let attempts = 1;
   77   const maxElapsedTime = 1800000; // 30 mins in ms
   78 
   79   // Loop until we receive a response that is not in progress,
   80   // or we receive something else than http status code 200.
   81   while (totalElaspedTime <= maxElapsedTime) {
   82     const graph = await getDepGraph(id, orgId);
   83 
   84     if (graph.data.attributes.in_progress) {
   85       const pollInterval = Math.min(minIntervalMs * attempts, maxIntervalMs);
   86       await sleep(pollInterval);
   87 
   88       totalElaspedTime += pollInterval;
   89       attempts++;
   90       continue;
   91     }
   92 
   93     return graph.data.attributes;
   94   }
   95 
   96   throw new Error('max retries reached');
   97 }
   98 
   99 async function fetchIssues(
  100   start_time,
  101   dep_graph_data,
  102   component_details,
  103   target_severity: SEVERITY,
  104   orgId: string,
  105 ) {
  106   const response: GetIssuesResponse = await getIssues(
  107     {
  108       dep_graph: dep_graph_data,
  109       start_time,
  110       component_details,
  111       target_severity,
  112     },
  113     orgId,
  114   );
  115 
  116   const issues = response.data.result.issues.map((issue) => {
  117     const converted = convertToCamelCase<Issue>(issue);
  118     converted.fixInfo = convertToCamelCase(converted.fixInfo);
  119     return converted;
  120   });
  121 
  122   const issuesData = convertMapCasing<{
  123     [issueId: string]: IssueDataUnmanaged;
  124   }>(response.data.result.issues_data);
  125 
  126   const depGraphData = convertDepGraph(response.data.result.dep_graph);
  127 
  128   const dependencyCount = response.data.result.dep_graph.graph.nodes.find(
  129     (graphNode) => {
  130       return graphNode.node_id === 'root-node';
  131     },
  132   )?.deps?.length;
  133 
  134   const depsFilePaths = response.data.result.deps_file_paths;
  135 
  136   const fileSignaturesDetails = convertMapCasing<FileSignaturesDetails>(
  137     response.data.result.file_signatures_details,
  138   );
  139 
  140   return {
  141     issues,
  142     issuesData,
  143     depGraphData,
  144     dependencyCount,
  145     depsFilePaths,
  146     fileSignaturesDetails,
  147   };
  148 }
  149 
  150 export async function resolveAndTestFactsUnmanagedDeps(
  151   scans: {
  152     [dir: string]: ScanResult[];
  153   },
  154   options: Options & PolicyOptions,
  155 ): Promise<[TestResult[], string[]]> {
  156   const results: any[] = [];
  157   const errors: string[] = [];
  158   const packageManager = 'Unmanaged (C/C++)';
  159   const displayTargetFile = '';
  160 
  161   const orgId = await getOrg(options.org);
  162   const target_severity: SEVERITY = options.severityThreshold || SEVERITY.LOW;
  163 
  164   if (orgId === '') {
  165     errors.push('organisation-id missing');
  166     return [results, errors];
  167   }
  168 
  169   for (const [path, scanResults] of Object.entries(scans)) {
  170     await spinner(`Resolving and Testing fileSignatures in ${path}`);
  171 
  172     for (const scanResult of scanResults) {
  173       try {
  174         const id = await submitHashes(
  175           { hashes: scanResult?.facts[0]?.data },
  176           orgId,
  177         );
  178 
  179         if (scanResult.analytics) {
  180           extractAndApplyPluginAnalytics(scanResult.analytics, id);
  181         }
  182 
  183         const {
  184           start_time,
  185           dep_graph_data,
  186           component_details,
  187         } = await pollDepGraphAttributes(id, orgId);
  188 
  189         const {
  190           issues,
  191           issuesData,
  192           depGraphData,
  193           dependencyCount,
  194           depsFilePaths,
  195           fileSignaturesDetails,
  196         } = await fetchIssues(
  197           start_time,
  198           dep_graph_data,
  199           component_details,
  200           target_severity,
  201           orgId,
  202         );
  203 
  204         const issuesMap: Map<string, Issue> = new Map();
  205         issues.forEach((i) => {
  206           issuesMap[i.issueId] = i;
  207         });
  208 
  209         const vulnerabilities: IssueDataUnmanaged[] = [];
  210         for (const issuesDataKey in issuesData) {
  211           const pkgCoordinate = `${issuesMap[issuesDataKey]?.pkgName}@${issuesMap[issuesDataKey]?.pkgVersion}`;
  212           const issueData = issuesData[issuesDataKey];
  213 
  214           issueData.from = [pkgCoordinate];
  215           issueData.name = pkgCoordinate;
  216           issueData.packageManager = packageManager;
  217           issueData.version = issuesMap[issuesDataKey]?.pkgVersion;
  218           issueData.upgradePath = [false];
  219           issueData.isPatchable = false;
  220           vulnerabilities.push(issueData);
  221         }
  222 
  223         const policy = await findAndLoadPolicy(path, 'cpp', options);
  224 
  225         const [issuesFiltered, issuesDataFiltered] = filterIgnoredIssues(
  226           issues,
  227           issuesData,
  228           policy,
  229         );
  230 
  231         extractAndApplyPluginAnalytics([
  232           {
  233             name: 'packageManager',
  234             data: depGraphData?.pkgManager?.name ?? '',
  235           },
  236           {
  237             name: 'unmanagedDependencyCount',
  238             data: depGraphData?.pkgs.length ?? 0,
  239           },
  240           {
  241             name: 'unmanagedIssuesCount',
  242             data: issues.length ?? 0,
  243           },
  244         ]);
  245 
  246         results.push({
  247           issues: issuesFiltered,
  248           issuesData: issuesDataFiltered,
  249           depGraphData,
  250           depsFilePaths,
  251           fileSignaturesDetails,
  252           vulnerabilities,
  253           path,
  254           dependencyCount,
  255           packageManager,
  256           displayTargetFile,
  257         });
  258       } catch (error) {
  259         const hasStatusCodeError = error.code >= 400 && error.code <= 500;
  260         if (hasStatusCodeError) {
  261           errors.push(error.message);
  262           continue;
  263         }
  264 
  265         const failedPath = path ? `in ${path}` : '.';
  266         errors.push(`Could not test dependencies ${failedPath}`);
  267       }
  268     }
  269   }
  270   spinner.clearAll();
  271   return [results, errors];
  272 }
  273 
  274 // resolveAndTestFactsRegistry has been deprecated, and will be removed in upcoming release.
  275 export async function resolveAndTestFactsRegistry(
  276   ecosystem: Ecosystem,
  277   scans: {
  278     [dir: string]: ScanResult[];
  279   },
  280   options: Options & PolicyOptions,
  281 ): Promise<[TestResult[], string[]]> {
  282   const results: any[] = [];
  283   const errors: string[] = [];
  284   const packageManager = 'Unmanaged (C/C++)';
  285   const displayTargetFile = '';
  286 
  287   for (const [path, scanResults] of Object.entries(scans)) {
  288     await spinner(`Resolving and Testing fileSignatures in ${path}`);
  289     for (const scanResult of scanResults) {
  290       try {
  291         const res = await requestTestPollingToken(options, true, scanResult);
  292         if (scanResult.analytics) {
  293           extractAndApplyPluginAnalytics(scanResult.analytics, res.token);
  294         }
  295         const { maxAttempts, pollInterval } = res.pollingTask;
  296         const attemptsCount = 0;
  297         const response = await pollingTestWithTokenUntilDone(
  298           res.token,
  299           ecosystem,
  300           options,
  301           pollInterval,
  302           attemptsCount,
  303           maxAttempts,
  304         );
  305 
  306         const policy = await findAndLoadPolicy(path, 'cpp', options);
  307         const [issues, issuesData] = filterIgnoredIssues(
  308           response.issues,
  309           response.issuesData,
  310           policy,
  311         );
  312 
  313         const issuesMap: Map<string, Issue> = new Map();
  314         response.issues.forEach((i) => {
  315           issuesMap[i.issueId] = i;
  316         });
  317 
  318         const vulnerabilities: IssueDataUnmanaged[] = [];
  319         for (const issuesDataKey in response.issuesData) {
  320           if (issuesMap[issuesDataKey]) {
  321             const issueData = response.issuesData[issuesDataKey];
  322             const pkgCoordinate = `${issuesMap[issuesDataKey].pkgName}@${issuesMap[issuesDataKey].pkgVersion}`;
  323             issueData.from = [pkgCoordinate];
  324             issueData.name = pkgCoordinate;
  325             issueData.packageManager = packageManager;
  326             issueData.version = issuesMap[issuesDataKey]?.pkgVersion;
  327             issueData.upgradePath = [false];
  328             issueData.isPatchable = false;
  329             vulnerabilities.push(issueData);
  330           }
  331         }
  332 
  333         const dependencyCount = response?.depGraphData?.graph?.nodes?.find(
  334           (graphNode) => {
  335             return graphNode.nodeId === 'root-node';
  336           },
  337         )?.deps?.length;
  338 
  339         results.push({
  340           issues,
  341           issuesData,
  342           depGraphData: response?.depGraphData,
  343           depsFilePaths: response?.depsFilePaths,
  344           fileSignaturesDetails: response?.fileSignaturesDetails,
  345           vulnerabilities,
  346           path,
  347           dependencyCount,
  348           packageManager,
  349           displayTargetFile,
  350         });
  351       } catch (error) {
  352         const hasStatusCodeError = error.code >= 400 && error.code <= 500;
  353         if (hasStatusCodeError) {
  354           errors.push(error.message);
  355           continue;
  356         }
  357         const failedPath = path ? `in ${path}` : '.';
  358         errors.push(`Could not test dependencies ${failedPath}`);
  359       }
  360     }
  361   }
  362   spinner.clearAll();
  363   return [results, errors];
  364 }