Skip to content

Implement declarative enums abstraction

Mehmet Emin INAC requested to merge provide_helper_to_register_enum_values into master

What does this MR do?

Instead of duplicating the logic all around the enum types, we can use this helper method to consolidate the logic which will remove the implementation details from the type classes and finally will make them more declarative and easy to reason about.

Usage of the new DSL

The whole point of the new DSL is to provide a way to centralize the place we define Enum values and make them easier to document. To do so we should first define the enum module(SSOT) and then register it to an Active Record model. We can also easily expose the enum values on GraphQL.

Defining an enum module

module DismissalReasons
  extend DeclarativeEnum

  key  :dismissal_reason
  name 'DismissalReasonOfVulnerability'

  description <<~TEXT
    This enum holds the user-selected dismissal reason
    when they are dismissing the vulnerabilities
  TEXT

  define do
    acceptable_risk value: 0, description: 'The vulnerability is known but is considered to be an acceptable business risk.'
    false_positive value: 1, description: 'An error in reporting the presence of a vulnerability in a system when the vulnerability is not present.'
    used_in_tests value: 2, description: 'The finding is not a vulnerability because it is part of a test or is test data.'
  end
end

Descriptions for the enum values are not required so you can omit them if not necessary(IMHO description is always good to have though);

module DismissalReasons
  extend DeclarativeEnum

  key  :dismissal_reason
  name 'DismissalReasonOfVulnerability'

  description <<~TEXT
    This enum holds the user-selected dismissal reason
    when they are dismissing the vulnerabilities
  TEXT

  define do
    acceptable_risk value: 0
    false_positive value: 1
    used_in_tests value: 2
  end
end

Extending Enum values on EE

We can use the prepend_if_ee helper method to extend the values of an Enum for the enterprise edition like so;

# app/enums/dismissal_reasons.rb

DismissalReasons.prepend_if_ee('EE::DismissalReasons')
# ee/app/enums/ee/dismissal_reasons.rb

module EE
  module DismissalReasons
    extend DeclarativeEnum

    define do
      not_applicable value: 3
    end
  end
end

This will extend the values of the DismissalReasons enum with the ones registered on the EE::DismissalReasons.

Registering the enum to an Active Record model;

class VulnerabilityFeedback
  declarative_enum DismissalReasons
end

This will use the key value set on the declarative enum to register the enum.

Exposing the enum values on GraphQL API;

This will expose all the values and their respective descriptions along with the name of the enum and description of the enum.

module Types
  module Vulnerabilities
    class DismissalReasonEnum < BaseEnum
      declarative_enum DismissalReasonEnum
    end
  end
end

Exposing the enum values on a different channel?

By promoting the Enum values to be a first-class citizen, we can open the doors for endless opportunities. If needed, we can also add documentation helpers for Grape endpoints or deprecating the enum values, etc.

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • [-] Label as security and @ mention @gitlab-com/gl-security/appsec
  • [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • [-] Security reports checked/validated by a reviewer from the AppSec team
Edited by Mehmet Emin INAC

Merge request reports

Loading