All files / app/assets/javascripts/security_configuration utils.js

95.83% Statements 23/24
77.77% Branches 14/18
100% Functions 7/7
95.65% Lines 22/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                              2x 7x 7x 7x             7x     7x 7x           7x 1x 1x     7x 1x     7x       7x       7x 7x         7x 7x 7x     7x                       2x 97x  
import { isEmpty } from 'lodash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { SCANNER_NAMES_MAP } from '~/security_configuration/constants';
import { REPORT_TYPE_DAST } from '~/vue_shared/security_reports/constants';
 
/**
 * This function takes in a arrays of features.
 * features is dynamic and coming from the backend.
 * securityFeatures is nested in features and are static arrays living in backend constants
 * This function takes the nested securityFeatures config and flattens it to the top level object.
 * It then filters out any scanner features that lack a security config for rednering in the UI
 * @param [{}] features
 * @returns {Object} Object with enriched features from constants divided into Security and Compliance Features
 */
 
export const augmentFeatures = (features = []) => {
  const featuresByType = features.reduce((acc, feature) => {
    acc[feature.type] = convertObjectPropsToCamelCase(feature, { deep: true });
    return acc;
  }, {});
 
  /**
   * Track feature configs that are used as nested elements in the UI
   * so they aren't rendered at the top level as a seperate card
   */
  const secondaryFeatures = [];
 
  // Modify each feature
  const augmentFeature = (feature) => {
    const augmented = {
      ...feature,
      ...featuresByType[feature.type],
    };
 
    // Secondary layer copies some values from the first layer
    if (augmented.secondary) {
      augmented.secondary = { ...augmented.secondary, ...featuresByType[feature.secondary.type] };
      secondaryFeatures.push(feature.secondary.type);
    }
 
    if (augmented.type === REPORT_TYPE_DAST && !augmented.onDemandAvailable) {
      delete augmented.badge;
    }
 
    Iif (augmented.badge && augmented.metaInfoPath) {
      augmented.badge.badgeHref = augmented.metaInfoPath;
    }
 
    return augmented;
  };
 
  // Filter out any features that lack a security feature definition or is used as a nested UI element
  const filterFeatures = (feature) => {
    return !secondaryFeatures.includes(feature.type) && !isEmpty(feature.securityFeatures || {});
  };
 
  // Convert backend provided properties to camelCase, and spread nested security config to the root
  // level for UI rendering.
  const flattenFeatures = (feature) => {
    const flattenedFeature = convertObjectPropsToCamelCase(feature, { deep: true });
    return augmentFeature({ ...flattenedFeature, ...flattenedFeature.securityFeatures });
  };
 
  return {
    augmentedSecurityFeatures: features.map(flattenFeatures).filter(filterFeatures),
  };
};
 
/**
 * Converts a list of security scanner IDs (such as SAST_IAC) into a list of their translated
 * names defined in the SCANNER_NAMES_MAP constant (eg. IaC Scanning).
 *
 * @param {String[]} scannerNames
 * @returns {String[]}
 */
export const translateScannerNames = (scannerNames = []) =>
  scannerNames.map((scannerName) => SCANNER_NAMES_MAP[scannerName] || scannerName);