diff --git a/lib/datadog/ci/ext/transport.rb b/lib/datadog/ci/ext/transport.rb index ece118eb..1810b62e 100644 --- a/lib/datadog/ci/ext/transport.rb +++ b/lib/datadog/ci/ext/transport.rb @@ -7,7 +7,10 @@ module Transport HEADER_DD_API_KEY = "DD-API-KEY" HEADER_CONTENT_TYPE = "Content-Type" HEADER_CONTENT_ENCODING = "Content-Encoding" + HEADER_EVP_SUBDOMAIN = "X-Datadog-EVP-Subdomain" + HEADER_CONTAINER_ID = "Datadog-Container-ID" + EVP_PROXY_PATH_PREFIX = "/evp_proxy/v2" TEST_VISIBILITY_INTAKE_HOST_PREFIX = "citestcycle-intake" TEST_VISIBILITY_INTAKE_PATH = "/api/v2/citestcycle" diff --git a/lib/datadog/ci/transport/api/base.rb b/lib/datadog/ci/transport/api/base.rb index 7ffc9703..eb62a2d9 100644 --- a/lib/datadog/ci/transport/api/base.rb +++ b/lib/datadog/ci/transport/api/base.rb @@ -11,7 +11,7 @@ def request(path:, payload:, verb: "post") private def headers - @headers ||= { + { Ext::Transport::HEADER_CONTENT_TYPE => Ext::Transport::CONTENT_TYPE_MESSAGEPACK } end diff --git a/lib/datadog/ci/transport/api/evp_proxy.rb b/lib/datadog/ci/transport/api/evp_proxy.rb new file mode 100644 index 00000000..e0706e19 --- /dev/null +++ b/lib/datadog/ci/transport/api/evp_proxy.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require_relative "base" +require_relative "../http" + +module Datadog + module CI + module Transport + module Api + class EVPProxy < Base + attr_reader :http + + def initialize(url:) + uri = URI.parse(url) + raise "Invalid evp proxy mode URL: #{url}" if uri.host.nil? + + @http = Datadog::CI::Transport::HTTP.new( + host: uri.host, + port: uri.port, + ssl: uri.scheme == "https" || uri.port == 443, + compress: false + ) + end + + def request(path:, payload:, verb: "post") + path = "#{Ext::Transport::EVP_PROXY_PATH_PREFIX}#{path}" + + http.request( + path: path, + payload: payload, + verb: verb, + headers: headers + ) + end + + private + + def container_id + return @container_id if defined?(@container_id) + + @container_id = Datadog::Core::Environment::Container.container_id + end + + def headers + headers = super + headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX + + c_id = container_id + headers[Ext::Transport::HEADER_CONTAINER_ID] = c_id unless c_id.nil? + + headers + end + end + end + end + end +end diff --git a/sig/datadog/ci/ext/transport.rbs b/sig/datadog/ci/ext/transport.rbs index 6c40b3b6..91f19a69 100644 --- a/sig/datadog/ci/ext/transport.rbs +++ b/sig/datadog/ci/ext/transport.rbs @@ -8,6 +8,12 @@ module Datadog HEADER_CONTENT_ENCODING: "Content-Encoding" + HEADER_EVP_SUBDOMAIN: "X-Datadog-EVP-Subdomain" + + HEADER_CONTAINER_ID: "Datadog-Container-ID" + + EVP_PROXY_PATH_PREFIX: "/evp_proxy/v2" + TEST_VISIBILITY_INTAKE_HOST_PREFIX: "citestcycle-intake" TEST_VISIBILITY_INTAKE_PATH: "/api/v2/citestcycle" diff --git a/sig/datadog/ci/transport/api/base.rbs b/sig/datadog/ci/transport/api/base.rbs index 32dfd6bc..c0467e33 100644 --- a/sig/datadog/ci/transport/api/base.rbs +++ b/sig/datadog/ci/transport/api/base.rbs @@ -3,8 +3,6 @@ module Datadog module Transport module Api class Base - @headers: Hash[String, String] - def request: (path: String, payload: String, ?verb: ::String) -> untyped private diff --git a/sig/datadog/ci/transport/api/evp_proxy.rbs b/sig/datadog/ci/transport/api/evp_proxy.rbs new file mode 100644 index 00000000..0da715c7 --- /dev/null +++ b/sig/datadog/ci/transport/api/evp_proxy.rbs @@ -0,0 +1,25 @@ +module Datadog + module CI + module Transport + module Api + class EVPProxy < Base + @http: Datadog::CI::Transport::HTTP + + @container_id: String? + + attr_reader http: Datadog::CI::Transport::HTTP + + def initialize: (url: String) -> void + + def request: (path: String, payload: String, ?verb: ::String) -> Datadog::CI::Transport::HTTP::ResponseDecorator + + private + + def container_id: () -> String? + + def headers: () -> Hash[String, String] + end + end + end + end +end diff --git a/spec/datadog/ci/transport/api/evp_proxy_spec.rb b/spec/datadog/ci/transport/api/evp_proxy_spec.rb new file mode 100644 index 00000000..30134fd1 --- /dev/null +++ b/spec/datadog/ci/transport/api/evp_proxy_spec.rb @@ -0,0 +1,87 @@ +require_relative "../../../../../lib/datadog/ci/transport/api/evp_proxy" + +RSpec.describe Datadog::CI::Transport::Api::EVPProxy do + subject do + described_class.new( + url: url + ) + end + + let(:url) { "http://localhost:5555" } + + let(:http) { double(:http) } + + describe "#initialize" do + context "with https URL" do + let(:url) { "https://citestcycle-intake.datad0ghq.com:443" } + + it "creates SSL transport" do + expect(Datadog::CI::Transport::HTTP).to receive(:new).with( + host: "citestcycle-intake.datad0ghq.com", + port: 443, + ssl: true, + compress: false + ).and_return(http) + + subject + end + end + + context "with http URL" do + it "creates http transport without SSL" do + expect(Datadog::CI::Transport::HTTP).to receive(:new).with( + host: "localhost", + port: 5555, + ssl: false, + compress: false + ).and_return(http) + + subject + end + end + end + + describe "#request" do + before do + allow(Datadog::CI::Transport::HTTP).to receive(:new).and_return(http) + expect(Datadog::Core::Environment::Container).to receive(:container_id).and_return(container_id) + end + + context "without container id" do + let(:container_id) { nil } + + it "produces correct headers and forwards request to HTTP layer" do + expect(http).to receive(:request).with( + path: "/evp_proxy/v2/path", + payload: "payload", + verb: "post", + headers: { + "Content-Type" => "application/msgpack", + "X-Datadog-EVP-Subdomain" => "citestcycle-intake" + } + ) + + subject.request(path: "/path", payload: "payload") + end + end + + context "with container id" do + let(:container_id) { "container-id" } + + it "produces correct headers and forwards request to HTTP layer" do + expect(http).to receive(:request).with( + path: "/evp_proxy/v2/path", + payload: "payload", + verb: "post", + headers: { + "Content-Type" => "application/msgpack", + "X-Datadog-EVP-Subdomain" => "citestcycle-intake", + "Datadog-Container-ID" => "container-id" + } + ) + + subject.request(path: "/path", payload: "payload") + end + end + end +end diff --git a/vendor/rbs/ddtrace/0/datadog/core/environment/container.rbs b/vendor/rbs/ddtrace/0/datadog/core/environment/container.rbs new file mode 100644 index 00000000..35f02b3d --- /dev/null +++ b/vendor/rbs/ddtrace/0/datadog/core/environment/container.rbs @@ -0,0 +1,29 @@ +module Datadog + module Core + module Environment + module Container + UUID_PATTERN: untyped + + CONTAINER_PATTERN: untyped + + PLATFORM_REGEX: untyped + + POD_REGEX: untyped + + CONTAINER_REGEX: untyped + + FARGATE_14_CONTAINER_REGEX: untyped + + Descriptor: untyped + + def self?.platform: () -> untyped + + def self?.container_id: () -> untyped + + def self?.task_uid: () -> untyped + + def self?.descriptor: () -> untyped + end + end + end +end \ No newline at end of file