secureCodeBox/secureCodeBox

View on GitHub
hooks/notification/hook/hook.ts

Summary

Maintainability
A
0 mins
Test Coverage
D
65%
// SPDX-FileCopyrightText: the secureCodeBox authors
//
// SPDX-License-Identifier: Apache-2.0
import { isMatch } from "lodash";
import { Finding } from "./model/Finding";
import { NotificationChannel } from "./model/NotificationChannel";
import { Notifier } from "./Notifier";
import { NotifierFactory } from "./NotifierFactory";
import { readFileSync } from "fs";
import * as jsyaml from "js-yaml";

const BASE_PATH = "/home/app/config";
const CHANNEL_FILE = `${BASE_PATH}/notification-channel.yaml`;

export async function handle({ getFindings, scan }) {
  let findings: Finding[] = await getFindings();
  let notificationChannels: NotificationChannel[] =
    getNotificationChannels(CHANNEL_FILE);
  let args: Object = getArgs();

  console.log("Starting notification hook");
  console.log(
    "Configured notification channels: " + notificationChannels.join(", ")
  );
  console.log(notificationChannels);
  for (const channel of notificationChannels) {
    console.log(
      `Starting notifier "${channel.name}" of type "${channel.type}"`
    );

    const findingsToNotify = findings.filter((finding) =>
      matches(finding, channel.rules)
    );

    if (
      channel.skipNotificationOnZeroFindings === true &&
      findingsToNotify.length === 0
    ) {
      console.log(
        `Skipping notifier "${channel.name}" as there are no findings to send the notification out for.`
      );
      continue;
    }

    const notifier: Notifier = NotifierFactory.create(
      channel,
      scan,
      findingsToNotify,
      args
    );
    await notifier.sendMessage();
  }
}

/**
 * Checks if a finding is matching a set of rules
 * @param finding
 * @param rules
 * @returns False if not matching, True if no rules specified or matching
 */
export function matches(finding: Finding, rules: any[]): boolean {
  if (rules == null || rules.length === 0) return true;
  for (let rule of rules) {
    if (doesNotMatch(rule, finding)) return false;
  }
  return true;
}

export function getNotificationChannels(channelFile: string): any[] {
  const yaml = readFileSync(channelFile);
  const notificationChannels = jsyaml.load(yaml.toString());
  return notificationChannels as any[];
}

function doesNotMatch(rule: any, finding: Finding): boolean {
  return !rule.matches.anyOf.some((condition: object) =>
    isMatch(finding, condition)
  );
}

function getArgs(): Object {
  return process.env;
}

export function mapToEndPoint(envName: string) {
  return process.env[envName];
}