From bec1d33c75cc194f9944ce32cc7c8f90d974fb08 Mon Sep 17 00:00:00 2001 From: Yury Lebedev Date: Thu, 6 Feb 2025 16:29:22 +0100 Subject: [PATCH] Remove reactive engine from AppSec --- lib/datadog/appsec/reactive/address_hash.rb | 22 ----- lib/datadog/appsec/reactive/engine.rb | 47 ---------- lib/datadog/appsec/reactive/subscriber.rb | 19 ---- sig/datadog/appsec/reactive/address_hash.rbs | 17 ---- sig/datadog/appsec/reactive/engine.rbs | 19 ---- sig/datadog/appsec/reactive/subscriber.rbs | 12 --- spec/datadog/appsec/reactive/engine_spec.rb | 94 ------------------- .../appsec/reactive/shared_examples.rb | 64 ------------- 8 files changed, 294 deletions(-) delete mode 100644 lib/datadog/appsec/reactive/address_hash.rb delete mode 100644 lib/datadog/appsec/reactive/engine.rb delete mode 100644 lib/datadog/appsec/reactive/subscriber.rb delete mode 100644 sig/datadog/appsec/reactive/address_hash.rbs delete mode 100644 sig/datadog/appsec/reactive/engine.rbs delete mode 100644 sig/datadog/appsec/reactive/subscriber.rbs delete mode 100644 spec/datadog/appsec/reactive/engine_spec.rb delete mode 100644 spec/datadog/appsec/reactive/shared_examples.rb diff --git a/lib/datadog/appsec/reactive/address_hash.rb b/lib/datadog/appsec/reactive/address_hash.rb deleted file mode 100644 index 7bda390c3b0..00000000000 --- a/lib/datadog/appsec/reactive/address_hash.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Datadog - module AppSec - module Reactive - # AddressHash for Reactive Engine - class AddressHash < Hash - def self.new(*arguments, &block) - super { |h, k| h[k] = [] } - end - - def addresses - keys.flatten - end - - def with(address) - keys.select { |k| k.include?(address) } - end - end - end - end -end diff --git a/lib/datadog/appsec/reactive/engine.rb b/lib/datadog/appsec/reactive/engine.rb deleted file mode 100644 index 92cfc9ecbf0..00000000000 --- a/lib/datadog/appsec/reactive/engine.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require_relative 'address_hash' -require_relative 'subscriber' - -module Datadog - module AppSec - module Reactive - # Reactive Engine - class Engine - def initialize - @data = {} - @subscribers = AddressHash.new - end - - def subscribe(*addresses, &block) - @subscribers[addresses.freeze] << Subscriber.new(&block) - end - - def publish(address, value) - # check if someone has address subscribed - if @subscribers.addresses.include?(address) - - # someone will be interested, set value - @data[address] = value - - # find candidates i.e address groups that contain the just posted address - @subscribers.with(address).each do |addresses| - # find targets to the address group containing the posted address - subscribers = @subscribers[addresses] - - # is all data for the targets available? - if (addresses - @data.keys).empty? - hash = addresses.each_with_object({}) { |a, h| h[a] = @data[a] } - subscribers.each { |s| s.call(*hash.values) } - end - end - end - end - - private - - attr_reader :subscribers, :data - end - end - end -end diff --git a/lib/datadog/appsec/reactive/subscriber.rb b/lib/datadog/appsec/reactive/subscriber.rb deleted file mode 100644 index e267ab95d76..00000000000 --- a/lib/datadog/appsec/reactive/subscriber.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Datadog - module AppSec - module Reactive - # Reactive Engine subscriber - class Subscriber - def initialize(&block) - @block = block - freeze - end - - def call(*args) - @block.call(*args) - end - end - end - end -end diff --git a/sig/datadog/appsec/reactive/address_hash.rbs b/sig/datadog/appsec/reactive/address_hash.rbs deleted file mode 100644 index f38aa1acf76..00000000000 --- a/sig/datadog/appsec/reactive/address_hash.rbs +++ /dev/null @@ -1,17 +0,0 @@ -module Datadog - module AppSec - module Reactive - class AddressHash < ::Hash[::Array[::String], ::Array[Subscriber]] - type key = ::Array[::String] - - def self.new: (*untyped arguments) -> AddressHash - - def []=: (key key, Subscriber value) -> Subscriber - - def addresses: () -> ::Array[::String] - - def with: (::String address) -> ::Array[key] - end - end - end -end diff --git a/sig/datadog/appsec/reactive/engine.rbs b/sig/datadog/appsec/reactive/engine.rbs deleted file mode 100644 index 5da0065c020..00000000000 --- a/sig/datadog/appsec/reactive/engine.rbs +++ /dev/null @@ -1,19 +0,0 @@ -module Datadog - module AppSec - module Reactive - class Engine - @data: ::Hash[::String, untyped] - @subscribers: AddressHash - - def initialize: () -> void - def subscribe: (*::String addresses) { (*untyped values) -> void } -> void - def publish: (::String address, top data) -> void - - private - - attr_reader subscribers: AddressHash - attr_reader data: ::Hash[::String, untyped] - end - end - end -end diff --git a/sig/datadog/appsec/reactive/subscriber.rbs b/sig/datadog/appsec/reactive/subscriber.rbs deleted file mode 100644 index a265a1f26e0..00000000000 --- a/sig/datadog/appsec/reactive/subscriber.rbs +++ /dev/null @@ -1,12 +0,0 @@ -module Datadog - module AppSec - module Reactive - class Subscriber - @block: ::Proc - - def initialize: () { () -> untyped } -> untyped - def call: (*untyped args) -> untyped - end - end - end -end diff --git a/spec/datadog/appsec/reactive/engine_spec.rb b/spec/datadog/appsec/reactive/engine_spec.rb deleted file mode 100644 index 8e52edeeb73..00000000000 --- a/spec/datadog/appsec/reactive/engine_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -require 'datadog/appsec/spec_helper' -require 'datadog/appsec/reactive/engine' - -RSpec.describe Datadog::AppSec::Reactive::Engine do - subject(:engine) { described_class.new } - let(:subscribers) { engine.send(:subscribers) } - let(:data) { engine.send(:data) } - - describe '#subscribe' do - it 'subscribes block to a list of addresses' do - expect(subscribers).to be_empty - engine.subscribe(:a, :b, :c) do - 1 + 1 - end - expect(subscribers).to_not be_empty - end - - it 'subscribes multiple times with same addresses appends subscribers' do - engine.subscribe(:a, :b, :c) do - 1 + 1 - end - expect(subscribers.size).to eq(1) - expect(subscribers[[:a, :b, :c]].size).to eq(1) - - engine.subscribe(:a, :b, :c) do - 2 + 2 - end - - expect(subscribers.size).to eq(1) - expect(subscribers[[:a, :b, :c]].size).to eq(2) - end - end - - describe '#publish' do - context 'when no address is subscribed' do - it 'is a no-op' do - expect do - engine.publish(:a, 1) - end.to_not(change { data }) - end - end - - context 'when an address is subscribed' do - it 'stores the data under the address' do - engine.subscribe(:a, :b, :c) do - 1 + 1 - end - - expect do - engine.publish(:a, 1) - end.to change { data[:a] }.from(nil).to(1) - end - - it 'executes subscribed block with published values when all addresses are published' do - expected_values = [] - engine.subscribe(:a, :b, :c) do |*values| - expected_values = values - 1 + 1 - end - - engine.publish(:a, 1) - engine.publish(:b, 2) - engine.publish(:c, 3) - - expect(expected_values).to eq([1, 2, 3]) - end - - context 'when multiple subscribers are present' do - it 'only publishes for the subscriber that matches all the keys when multiple subscribers are present' do - expected_values = [] - engine.subscribe(:a, :b, :c) do |*values| - expected_values = values - 1 + 1 - end - - engine.subscribe(:a, :d, :e) do |*values| - expected_values = values - 1 + 1 - end - - engine.publish(:a, 1) - engine.publish(:d, 4) - engine.publish(:e, 5) - engine.publish(:b, 2) - engine.publish(:c, 3) - - expect(expected_values).to eq([1, 2, 3]) - end - end - end - end -end diff --git a/spec/datadog/appsec/reactive/shared_examples.rb b/spec/datadog/appsec/reactive/shared_examples.rb deleted file mode 100644 index 98136c4f2dc..00000000000 --- a/spec/datadog/appsec/reactive/shared_examples.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples 'waf result' do - context 'is a match' do - it 'yields result and no blocking action' do - waf_result = Datadog::AppSec::SecurityEngine::Result::Match.new( - events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0 - ) - - expect(engine).to receive(:subscribe).and_call_original - expect(appsec_context).to receive(:run_waf).and_return(waf_result) - - described_class.subscribe(engine, appsec_context) do |result| - expect(result).to eq(waf_result) - end - expect(described_class.publish(engine, gateway)).to be_nil - end - - it 'yields result and blocking action. The publish method catches the resul as well' do - actions = { 'block_request' => { 'grpc_status_code' => '10', 'status_code' => '403', 'type' => 'auto' } } - waf_result = Datadog::AppSec::SecurityEngine::Result::Match.new( - events: [], actions: actions, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0 - ) - - expect(engine).to receive(:subscribe).and_call_original - expect(appsec_context).to receive(:run_waf).and_return(waf_result) - - described_class.subscribe(engine, appsec_context) do |result| - expect(result).to eq(waf_result) - end - expect(described_class.publish(engine, gateway)).to eq(true) - end - end - - context 'is ok' do - let(:waf_result) do - Datadog::AppSec::SecurityEngine::Result::Ok.new( - events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0 - ) - end - - it 'does not yield' do - expect(engine).to receive(:subscribe).and_call_original - expect(appsec_context).to receive(:run_waf).and_return(waf_result) - expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control - - expect(described_class.publish(engine, gateway)).to be_nil - end - end - - context 'is invalid_call' do - let(:waf_result) do - Datadog::AppSec::SecurityEngine::Result::Error.new(duration_ext_ns: 0) - end - - it 'does not yield' do - expect(engine).to receive(:subscribe).and_call_original - expect(appsec_context).to receive(:run_waf).and_return(waf_result) - expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control - - expect(described_class.publish(engine, gateway)).to be_nil - end - end -end