From 28ed896bef7853172f26eecd8a2bd9618adb14ed Mon Sep 17 00:00:00 2001
From: Hitesh Raghuvanshi <hraghuvanshi@gitlab.com>
Date: Tue, 6 Feb 2024 14:45:03 +0530
Subject: [PATCH] Added table and model for instance level destination

Changelog: added
EE: true
---
 ...stance_external_streaming_destinations.yml | 10 +++++++
 ...nstance_external_streaming_destinations.rb | 16 +++++++++++
 db/schema_migrations/20240130162148           |  1 +
 db/structure.sql                              | 26 ++++++++++++++++++
 .../external_streaming_destination.rb         | 16 +++++++++++
 ...instance_external_streaming_destination.rb | 10 +++++++
 .../external_streaming_destination_spec.rb    | 27 +++++++++++++++++++
 7 files changed, 106 insertions(+)
 create mode 100644 db/docs/audit_events_instance_external_streaming_destinations.yml
 create mode 100644 db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb
 create mode 100644 db/schema_migrations/20240130162148
 create mode 100644 ee/app/models/audit_events/instance/external_streaming_destination.rb
 create mode 100644 ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb
 create mode 100644 ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb

diff --git a/db/docs/audit_events_instance_external_streaming_destinations.yml b/db/docs/audit_events_instance_external_streaming_destinations.yml
new file mode 100644
index 0000000000000..966e89284462b
--- /dev/null
+++ b/db/docs/audit_events_instance_external_streaming_destinations.yml
@@ -0,0 +1,10 @@
+---
+table_name: audit_events_instance_external_streaming_destinations
+classes:
+- AuditEvents::Instance::ExternalStreamingDestination
+feature_categories:
+- audit_events
+description: Stores external audit event destinations configurations for instance.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141739
+milestone: '16.9'
+gitlab_schema: gitlab_main_clusterwide
diff --git a/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb b/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb
new file mode 100644
index 0000000000000..2f1d906767726
--- /dev/null
+++ b/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateAuditEventsInstanceExternalStreamingDestinations < Gitlab::Database::Migration[2.2]
+  milestone '16.9'
+
+  def change
+    create_table :audit_events_instance_external_streaming_destinations do |t|
+      t.timestamps_with_timezone null: false
+      t.integer :type, null: false, limit: 2
+      t.text :name, null: false, limit: 72
+      t.jsonb :config, null: false
+      t.binary :encrypted_secret_token, null: false
+      t.binary :encrypted_secret_token_iv, null: false
+    end
+  end
+end
diff --git a/db/schema_migrations/20240130162148 b/db/schema_migrations/20240130162148
new file mode 100644
index 0000000000000..593bb247644f0
--- /dev/null
+++ b/db/schema_migrations/20240130162148
@@ -0,0 +1 @@
+37166b2aa9addf6d1effd34da3242866a13c9a24636f0be677d72c89bc09376d
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index bf51d637ab169..456d47abb8d3e 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -13222,6 +13222,27 @@ CREATE SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq
 
 ALTER SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq OWNED BY audit_events_instance_external_audit_event_destinations.id;
 
+CREATE TABLE audit_events_instance_external_streaming_destinations (
+    id bigint NOT NULL,
+    created_at timestamp with time zone NOT NULL,
+    updated_at timestamp with time zone NOT NULL,
+    type smallint NOT NULL,
+    name text NOT NULL,
+    config jsonb NOT NULL,
+    encrypted_secret_token bytea NOT NULL,
+    encrypted_secret_token_iv bytea NOT NULL,
+    CONSTRAINT check_219decfb51 CHECK ((char_length(name) <= 72))
+);
+
+CREATE SEQUENCE audit_events_instance_external_streaming_destinations_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+ALTER SEQUENCE audit_events_instance_external_streaming_destinations_id_seq OWNED BY audit_events_instance_external_streaming_destinations.id;
+
 CREATE TABLE audit_events_instance_google_cloud_logging_configurations (
     id bigint NOT NULL,
     created_at timestamp with time zone NOT NULL,
@@ -27021,6 +27042,8 @@ ALTER TABLE ONLY audit_events_instance_amazon_s3_configurations ALTER COLUMN id
 
 ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_external_audit_event_destinations_id_seq'::regclass);
 
+ALTER TABLE ONLY audit_events_instance_external_streaming_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_external_streaming_destinations_id_seq'::regclass);
+
 ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_google_cloud_logging_configuration_id_seq'::regclass);
 
 ALTER TABLE ONLY audit_events_streaming_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_event_type_filters_id_seq'::regclass);
@@ -28994,6 +29017,9 @@ ALTER TABLE ONLY audit_events_instance_amazon_s3_configurations
 ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations
     ADD CONSTRAINT audit_events_instance_external_audit_event_destinations_pkey PRIMARY KEY (id);
 
+ALTER TABLE ONLY audit_events_instance_external_streaming_destinations
+    ADD CONSTRAINT audit_events_instance_external_streaming_destinations_pkey PRIMARY KEY (id);
+
 ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations
     ADD CONSTRAINT audit_events_instance_google_cloud_logging_configurations_pkey PRIMARY KEY (id);
 
diff --git a/ee/app/models/audit_events/instance/external_streaming_destination.rb b/ee/app/models/audit_events/instance/external_streaming_destination.rb
new file mode 100644
index 0000000000000..070dda144eb61
--- /dev/null
+++ b/ee/app/models/audit_events/instance/external_streaming_destination.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module AuditEvents
+  module Instance
+    class ExternalStreamingDestination < ApplicationRecord
+      include Limitable
+      include ExternallyStreamable
+
+      self.limit_name = 'external_audit_event_destinations'
+      self.limit_scope = Limitable::GLOBAL_SCOPE
+      self.table_name = 'audit_events_instance_external_streaming_destinations'
+
+      validates :name, uniqueness: true
+    end
+  end
+end
diff --git a/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb b/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb
new file mode 100644
index 0000000000000..67d38cf027056
--- /dev/null
+++ b/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+  factory :audit_events_instance_external_streaming_destination,
+    class: 'AuditEvents::Instance::ExternalStreamingDestination' do
+    type { 'http' }
+    config { { url: 'https://www.example.com' } }
+    secret_token { 'hello' }
+  end
+end
diff --git a/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb b/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb
new file mode 100644
index 0000000000000..1dd38cfac8698
--- /dev/null
+++ b/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AuditEvents::Instance::ExternalStreamingDestination, feature_category: :audit_events do
+  subject(:destination) { build(:audit_events_instance_external_streaming_destination) }
+
+  describe 'Validations' do
+    it 'validates uniqueness of name scoped to namespace' do
+      create(:audit_events_instance_external_streaming_destination, name: 'Test Destination')
+      destination = build(:audit_events_instance_external_streaming_destination, name: 'Test Destination')
+
+      expect(destination).not_to be_valid
+      expect(destination.errors.full_messages).to include('Name has already been taken')
+    end
+  end
+
+  it_behaves_like 'includes Limitable concern' do
+    subject { build(:audit_events_instance_external_streaming_destination) }
+  end
+
+  it_behaves_like 'includes ExternallyStreamable concern' do
+    subject { build(:audit_events_instance_external_streaming_destination) }
+
+    let(:model_factory_name) { :audit_events_instance_external_streaming_destination }
+  end
+end
-- 
GitLab