Welcome to mirror list, hosted at ThFree Co, Russian Federation.

definition.rb « type « audit « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 772023616b82726dd30e341ca45005762f130b28 (plain)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# frozen_string_literal: true

module Gitlab
  module Audit
    module Type
      class Definition
        include ActiveModel::Validations
        include ::Gitlab::Audit::Type::Shared

        attr_reader :path
        attr_reader :attributes

        validate :validate_schema
        validate :validate_file_name

        def self.declarative_policy_class
          'AuditEvents::DefinitionPolicy'
        end

        InvalidAuditEventTypeError = Class.new(StandardError)

        AUDIT_EVENT_TYPE_SCHEMA_PATH = Rails.root.join('config', 'audit_events', 'types', 'type_schema.json')
        AUDIT_EVENT_TYPE_SCHEMA = JSONSchemer.schema(AUDIT_EVENT_TYPE_SCHEMA_PATH)

        PARAMS.each do |param|
          define_method(param) do
            attributes[param]
          end
        end

        def initialize(path, opts = {})
          @path = path
          @attributes = {}

          # assign nil, for all unknown opts
          PARAMS.each do |param|
            @attributes[param] = opts[param]
          end
        end

        def key
          name.to_sym
        end

        private

        def validate_schema
          schema_errors = AUDIT_EVENT_TYPE_SCHEMA
                            .validate(attributes.to_h.deep_stringify_keys)
                            .map { |error| JSONSchemer::Errors.pretty(error) }

          errors.add(:base, schema_errors) if schema_errors.present?
        end

        def validate_file_name
          # ignoring Style/GuardClause because if we move this into one line, we cause Layout/LineLength errors
          # rubocop:disable Style/GuardClause
          unless File.basename(path, ".yml") == name
            errors.add(:base, "Audit event type '#{name}' has an invalid path: '#{path}'. " \
              "'#{name}' must match the filename")
          end
          # rubocop:enable Style/GuardClause
        end

        class << self
          include ::Gitlab::Utils::StrongMemoize

          def paths
            @paths ||= [Rails.root.join('config', 'audit_events', 'types', '*.yml')]
          end

          def definitions
            load_all!
          end
          strong_memoize_attr :definitions

          def get(key)
            definitions[key.to_sym]
          end

          def event_names
            definitions.keys.map(&:to_s)
          end

          def names_with_category
            definitions.map do |event_name, value|
              { event_name: event_name, feature_category: value.attributes[:feature_category] }
            end
          end

          def defined?(key)
            get(key).present?
          end

          def stream_only?(key)
            event_definition = get(key)
            return false unless event_definition

            event_definition.streamed && !event_definition.saved_to_database
          end

          private

          def load_all!
            paths.each_with_object({}) do |glob_path, definitions|
              load_all_from_path!(definitions, glob_path)
            end
          end

          def load_all_from_path!(definitions, glob_path)
            Dir.glob(glob_path).each do |path|
              definition = load_from_file(path)

              if previous = definitions[definition.key]
                raise InvalidAuditEventTypeError, "Audit event type '#{definition.key}' " \
                  "is already defined in '#{previous.path}'"
              end

              definitions[definition.key] = definition
            end
          end

          def load_from_file(path)
            definition = File.read(path)
            definition = YAML.safe_load(definition)
            definition.deep_symbolize_keys!

            new(path, definition).tap(&:validate!)
          rescue StandardError => e
            raise InvalidAuditEventTypeError, "Invalid definition for `#{path}`: #{e.message}"
          end
        end
      end
    end
  end
end

Gitlab::Audit::Type::Definition.prepend_mod