Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Vulnerabilities dashboard] Create the Dashboard tab using OSD plugins #5894

Closed
3 tasks
Tracked by #5763
Machi3mfl opened this issue Sep 18, 2023 · 5 comments · Fixed by #5966
Closed
3 tasks
Tracked by #5763

[Vulnerabilities dashboard] Create the Dashboard tab using OSD plugins #5894

Machi3mfl opened this issue Sep 18, 2023 · 5 comments · Fixed by #5966
Assignees
Labels
level/subtask Subtask issue type/enhancement Enhancement issue

Comments

@Machi3mfl
Copy link
Member

Machi3mfl commented Sep 18, 2023

Description

Create the Dashboard tab using OSD plugins

image

Tasks

  • Create visualization definitions using the OSD Visualize plugin (2.9.0) and the new vulnerabilities index pattern.
  • Use the dashboard plugin react component to render the vis definitions created in the previous step
  • Add a searchbar component to filter the events
@Machi3mfl Machi3mfl changed the title Create Dashboard tab using opensearch plugins (Dashboard/Embeddables/Visualizations Builder) - More details below [Vulnerabilities dashboard] Create Dashboard tab using opensearch plugins Sep 18, 2023
@Machi3mfl Machi3mfl changed the title [Vulnerabilities dashboard] Create Dashboard tab using opensearch plugins [Vulnerabilities dashboard] Create the Dashboard tab using opensearch plugins Sep 18, 2023
@Machi3mfl Machi3mfl changed the title [Vulnerabilities dashboard] Create the Dashboard tab using opensearch plugins [Vulnerabilities dashboard] Create the Dashboard tab using OSD plugins Sep 18, 2023
@Machi3mfl Machi3mfl added level/subtask Subtask issue type/enhancement Enhancement issue labels Sep 18, 2023
@wazuhci wazuhci moved this to Triage in Release 4.8.0 Sep 18, 2023
@wazuhci wazuhci moved this from Triage to In progress in Release 4.8.0 Sep 20, 2023
@jbiset
Copy link
Member

jbiset commented Sep 26, 2023

Progress

Progress has been made on the Dashboard tab within the vulnerability module. Visualizations have been implemented using the "renderer embeddable by value" feature of the OpenSearch Dashboards dashboard plugin. Below is a demo image illustrating the current state of the vulnerability module dashboard with example data.

NewVulnerabilityImage_A

NewVulnerabilityImage_B

The search bar shown in the demo image, which is currently in place, will be replaced by the native search bar of OpenSearch Dashboard. This search bar effectively communicates with the visualizations on the dashboard. The data for these visualizations is sourced from the wazuh-inventory-cve-4.x index (wazuh-inventory-cve-* index pattern), while the "Open vs. Close" visualization is powered by the wazuh-alerts-* index pattern.

@jbiset
Copy link
Member

jbiset commented Oct 9, 2023

Update top filters and KPIs dashboards

wazuh_vulnerability_dashboard_filter_tables_version_A

wazuh_vulnerability_dashboard_filter_tables_version_B

@jbiset
Copy link
Member

jbiset commented Oct 12, 2023

Analysis and solution of the bad request problem

The Embeddables' Container class plays a central role in configuring the different panels of the dashboard. This is where the final adjustments to inputs are made and they are added to the dashboard as panels one by one, rendering based on the corresponding factory obtained through the panel's "type" property.

The "OnPanelAdded(panel: PanelState)" method of the Container class (extended by DashboardContainer) receives a "PanelState" object. From this object, the appropriate factory is extracted based on the type, and either "factory.createFromSavedObject" or "factory.create" is called depending on the presence of a "savedObjectId" in the input.

In the specific case of using "DashboardContainerByValueRenderer" and given that the panel type is "visualization", the "create" method of "VisualizeEmbeddableFactory" is invoked.

The "create(input: VisualizeInput & { savedVis?: SerializedVis }, parent?: IContainer)" method of the VisualizeEmbeddableFactory class takes the input processed by the Container and the parent object as parameters to create and return the embeddable of the corresponding type, in this case, a visualization.

Being an embeddable by value, the "create" method calls "createVisEmbeddableFromObject(this.deps)" to create the embeddable using the input, an instance of Vis (created with the type and savedVis from the input), an array of savedVisualizations, attribute services, and the parent object.

The return from "createVisEmbeddableFromObject" is an instance of VisualizeEmbeddable. However, a problem arises here. VisualizeEmbeddable has an "updateHandler" method to propagate detected changes. Additionally, when the "shouldFetchVisLayers" condition is met, it executes the "populateVisLayers" method, which makes a fetch request to obtain the "augmentVisSavedObjs", sometimes resulting in a 400 error as shown in the provided image.

Error_Augment-vis

The critical point leading to a 400 error in the GET request occurs within the getAugmentVisSavedObjs function called by fetchVisLayers in the populateVisLayers process

fetchVisLayers method code
/**
 * Collects any VisLayers from plugin expressions functions
 * by fetching all AugmentVisSavedObjects that meets below criteria:
 * - includes a reference to the vis saved object id
 * - includes any of the plugin resource IDs, if specified
 */
fetchVisLayers = async (): Promise<VisLayers> => {
  try {
    const expressionParams: IExpressionLoaderParams = {
      searchContext: {
        timeRange: this.timeRange,
        query: this.input.query,
        filters: this.input.filters,
      },
      uiState: this.vis.uiState,
      inspectorAdapters: this.inspectorAdapters,
    };
    const aborted = get(this.abortController, 'signal.aborted', false) as boolean;
    const augmentVisSavedObjs = await getAugmentVisSavedObjs(
      this.vis.id,
      this.savedAugmentVisLoader,
      undefined,
      this.visAugmenterConfig?.visLayerResourceIds
    );

    if (!isEmpty(augmentVisSavedObjs) && !aborted && isEligibleForVisLayers(this.vis)) {
      const visLayersPipeline = buildPipelineFromAugmentVisSavedObjs(augmentVisSavedObjs);
      // The initial input for the pipeline will just be an empty arr of VisLayers. As plugin
      // expression functions are ran, they will incrementally append their generated VisLayers to it.
      const visLayersPipelineInput = {
        type: 'vis_layers',
        layers: [] as VisLayers,
      };
      // We cannot use this.handler in this case, since it does not support the run() cmd
      // we need here. So, we consume the expressions service to run this directly instead.
      const exprVisLayers = (await getExpressions().run(
        visLayersPipeline,
        visLayersPipelineInput,
        expressionParams as Record<string, unknown>
      )) as ExprVisLayers;
      const visLayers = exprVisLayers.layers;

      /**
       * There may be some stale saved objs if any plugin resources have been deleted since last time
       * data was fetched from them via the expression functions. Execute this trigger so any listening
       * action can perform cleanup.
       *
       * TODO: this should be automatically handled by the saved objects plugin. Tracking issue:
       * https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4499
       */
      getUiActions().getTrigger(PLUGIN_RESOURCE_DELETE_TRIGGER).exec({
        savedObjs: augmentVisSavedObjs,
        visLayers,
      });

      const err = getAnyErrors(visLayers, this.vis.title);
      // This is only true when one or more VisLayers has an error
      if (err !== undefined) {
        const { toasts } = getNotifications();
        toasts.addError(err, {
          title: i18n.translate('visualizations.renderVisTitle', {
            defaultMessage: `Error loading data on the ${this.vis.title} chart`,
          }),
          toastMessage: ' ',
          id: this.id,
        });
      }
      return visLayers;
    }
  } catch {
    return [] as VisLayers;
  }
  return [] as VisLayers;
};

It's essential to specify at least one ID in the savedVis object within the visualization definition. Failure to do so will result in an error when generating a bad request, as the this.vis.id parameter received by getAugmentVisSavedObjs will lack the necessary value

@jbiset
Copy link
Member

jbiset commented Oct 17, 2023

Vulnerability Dashboard alternatives to "Open vs Close" chart

Alternative 1 - Alerts by agents

wazuh_vulnerability_dashboard_filter_tables_version_A_alternative1

Alternative 2 - Alerts by agents + Agents by severity

wazuh_vulnerability_dashboard_filter_tables_version_A_alternative2

@wazuhci wazuhci moved this from In progress to In review in Release 4.8.0 Oct 25, 2023
@jbiset jbiset closed this as completed Oct 25, 2023
@jbiset
Copy link
Member

jbiset commented Oct 25, 2023

Last version

Light mode

Vulnerability_Detection_light_(part1)

Vulnerability_Detection_light_(part2)

Dark mode

Vulnerability_Detection_dark_(part1)

Vulnerability_Detection_dark_(part2)

@wazuhci wazuhci moved this from In review to Done in Release 4.8.0 Oct 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
level/subtask Subtask issue type/enhancement Enhancement issue
Projects
No open projects
Archived in project
2 participants