"Fossies" - the Fresh Open Source Software Archive

Member "cli-1.1280.1/src/lib/plugins/sast/index.ts" (20 Feb 2024, 6793 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 chalk from 'chalk';
    2 import * as Sarif from 'sarif';
    3 import * as debugLib from 'debug';
    4 import { v4 as uuidv4 } from 'uuid';
    5 import { getCodeTestResults } from './analysis';
    6 import { getSastSettings } from './settings';
    7 import {
    8   getCodeDisplayedOutput,
    9   getPrefix,
   10   getMeta,
   11 } from './format/output-format';
   12 import { EcosystemPlugin } from '../../ecosystems/types';
   13 import { FailedToRunTestError, NoSupportedSastFiles } from '../../errors';
   14 import { CodeClientErrorWithDetail, CodeClientError } from './errors';
   15 import { filterIgnoredIssues } from './utils';
   16 import { jsonStringifyLargeObject } from '../../json';
   17 import * as analytics from '../../analytics';
   18 import * as cloneDeep from 'lodash.clonedeep';
   19 
   20 const debug = debugLib('snyk-code');
   21 
   22 export const codePlugin: EcosystemPlugin = {
   23   // We currently don't use scan/display. we will need to consolidate ecosystem plugins
   24   // to accept flows that act differently in the `testDependencies` step, as we have here
   25   async scan() {
   26     return null as any;
   27   },
   28   async display() {
   29     return '';
   30   },
   31   async test(paths, options) {
   32     const requestId = uuidv4();
   33     debug(`Request ID: ${requestId}`);
   34     try {
   35       analytics.add('sast-scan', true);
   36       const sastSettings = await getSastSettings(options);
   37       // Currently code supports only one path
   38       const path = paths[0];
   39 
   40       const testResults = await getCodeTestResults(
   41         path,
   42         options,
   43         sastSettings,
   44         requestId,
   45       );
   46 
   47       if (!testResults) {
   48         throw new NoSupportedSastFiles();
   49       }
   50 
   51       // cloneDeep is used so the sarif is not changed when using the testResults getting the displayed output
   52       const sarifTypedResult = cloneDeep(
   53         testResults?.analysisResults?.sarif,
   54       ) as Sarif.Log;
   55       const sarifRunResults = sarifTypedResult.runs?.[0].results ?? [];
   56 
   57       // Report flow includes ignored issues (suppressions) in the results.
   58       const hasIgnoredIssues = options['report'] ?? false;
   59 
   60       // If suppressions are included in results filter them out to get real issue count
   61       const foundIssues = hasIgnoredIssues
   62         ? filterIgnoredIssues(sarifRunResults)
   63         : sarifRunResults;
   64       const numOfIssues = foundIssues.length || 0;
   65       analytics.add('sast-issues-found', numOfIssues);
   66 
   67       let newOrg = options.org;
   68       if (!newOrg && sastSettings.org) {
   69         newOrg = sastSettings.org;
   70       }
   71       const meta = getMeta({ ...options, org: newOrg }, path);
   72       const prefix = getPrefix(path);
   73       let readableResult = getCodeDisplayedOutput({
   74         testResults,
   75         meta,
   76         prefix,
   77         shouldFilterIgnored: hasIgnoredIssues,
   78       });
   79 
   80       if (options['no-markdown']) {
   81         sarifRunResults.forEach(({ message }) => {
   82           delete message.markdown;
   83         });
   84       }
   85 
   86       const shouldStringifyResult =
   87         options['sarif-file-output'] ||
   88         options.sarif ||
   89         options['json-file-output'] ||
   90         options.json;
   91       const stringifiedResult = shouldStringifyResult
   92         ? jsonStringifyLargeObject(sarifTypedResult)
   93         : '';
   94 
   95       let sarifResult: string | undefined;
   96       if (options['sarif-file-output']) {
   97         sarifResult = stringifiedResult;
   98       }
   99       let jsonResult: string | undefined;
  100       if (options['json-file-output']) {
  101         jsonResult = stringifiedResult;
  102       }
  103       if (options.sarif || options.json) {
  104         readableResult = stringifiedResult;
  105       }
  106 
  107       if (numOfIssues > 0) {
  108         throwIssuesError({ readableResult, sarifResult, jsonResult });
  109       }
  110 
  111       return sarifResult ? { readableResult, sarifResult } : { readableResult };
  112     } catch (error) {
  113       let err: Error;
  114       if (isCodeClientErrorWithDetail(error)) {
  115         err = resolveCodeClientErrorWithDetail(error);
  116       } else if (isCodeClientError(error)) {
  117         err = resolveCodeClientError(error);
  118       } else if (error instanceof Error) {
  119         err = error;
  120       } else if (isUnauthorizedError(error)) {
  121         err = new FailedToRunTestError(error.message, error.code);
  122       } else {
  123         err = new Error(error);
  124       }
  125       debug(
  126         chalk.bold.red(
  127           `requestId: ${requestId} statusCode:${error.code ||
  128             error.statusCode}, message: ${error.statusText || error.message}`,
  129         ),
  130       );
  131       throw err;
  132     }
  133   },
  134 };
  135 
  136 function isCodeClientError(error: object): boolean {
  137   return (
  138     error.hasOwnProperty('statusCode') &&
  139     error.hasOwnProperty('statusText') &&
  140     error.hasOwnProperty('apiName')
  141   );
  142 }
  143 
  144 const genericErrorHelpMessages = {
  145   500: "One or more of Snyk's services may be temporarily unavailable.",
  146   502: "One or more of Snyk's services may be temporarily unavailable.",
  147 };
  148 
  149 const apiSpecificErrorHelpMessages = {
  150   initReport: {
  151     ...genericErrorHelpMessages,
  152     400: 'Make sure this feature is enabled by contacting support.',
  153   },
  154   getReport: {
  155     ...genericErrorHelpMessages,
  156     'Analysis result set too large':
  157       'The findings for this project may exceed the allowed size limit.',
  158   },
  159 };
  160 
  161 function resolveCodeClientError(error: {
  162   apiName: string;
  163   statusCode: number;
  164   statusText: string;
  165 }): Error {
  166   // For now only report includes custom client errors
  167   if (error.apiName === 'initReport' || error.apiName === 'getReport') {
  168     const additionalHelp =
  169       apiSpecificErrorHelpMessages[error.apiName][error.statusText] ??
  170       apiSpecificErrorHelpMessages[error.apiName][error.statusCode];
  171 
  172     return new CodeClientError(
  173       error.statusCode,
  174       error.statusText,
  175       additionalHelp,
  176     );
  177   }
  178   const isUnauthorized = isUnauthorizedError(error) ? 'Unauthorized: ' : '';
  179   return new FailedToRunTestError(
  180     `${isUnauthorized}Failed to run 'code test'`,
  181     error.statusCode,
  182   );
  183 }
  184 
  185 function resolveCodeClientErrorWithDetail(error: any) {
  186   return new CodeClientErrorWithDetail(
  187     error.statusText,
  188     error.statusCode,
  189     error.detail,
  190   );
  191 }
  192 
  193 function isCodeClientErrorWithDetail(error: any): boolean {
  194   return (
  195     error.hasOwnProperty('statusCode') &&
  196     error.hasOwnProperty('statusText') &&
  197     error.hasOwnProperty('detail') &&
  198     error.hasOwnProperty('apiName')
  199   );
  200 }
  201 
  202 function isUnauthorizedError(error: any): boolean {
  203   return (
  204     error.statusCode === 401 ||
  205     error.statusCode === 403 ||
  206     error.code === 403 ||
  207     error.code === 401
  208   );
  209 }
  210 
  211 function throwIssuesError(args: {
  212   readableResult: string;
  213   sarifResult: string | undefined;
  214   jsonResult: string | undefined;
  215 }): Error {
  216   const err = new Error(args.readableResult) as any;
  217   err.code = 'VULNS';
  218   if (args.sarifResult !== undefined) {
  219     err.sarifStringifiedResults = args.sarifResult;
  220   }
  221   if (args.jsonResult !== undefined) {
  222     err.jsonStringifiedResults = args.jsonResult;
  223   }
  224   throw err;
  225 }