# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/reporting/reporting_events/architecture_component' require 'contrast/agent/reporting/reporting_events/library_discovery' require 'contrast/agent/reporting/reporting_events/reporting_event' require 'contrast/agent/reporting/reporting_events/route_discovery' require 'contrast/api/dtm.pb' require 'contrast/components/logger' require 'json' module Contrast module Agent module Reporting # This is the new Application Update class which will include all the needed information for the new reporting # system. Contains data used by TeamServer to render the Flow Map and SCA features. # # @attr_reader components [Array<Contrast::Agent::Reporting::ArchitectureComponent>] # @attr_reader libraries [Array<Contrast::Agent::Reporting::LibraryDiscovery>] class ApplicationUpdate < Contrast::Agent::Reporting::ReportingEvent attr_reader :components, :libraries class << self # @param app_update_dtm [Contrast::Api::Dtm::ApplicationUpdate] # @return [Contrast::Agent::Reporting::ApplicationUpdate] def convert app_update_dtm report = new report.attach_data(app_update_dtm) report end end def initialize @event_method = :PUT @event_endpoint = "#{ Contrast::API.api_url }/api/ng/update/application" super end # Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly. # # @param app_update_dtm [Contrast::Api::Dtm::ApplicationUpdate] def attach_data app_update_dtm @components = app_update_dtm.components.map do |component| Contrast::Agent::Reporting::ArchitectureComponent.convert(component) end @libraries = app_update_dtm.libraries.values.map do |library| Contrast::Agent::Reporting::LibraryDiscovery.convert(library) end end # Convert the instance variables on the class, and other information, into the identifiers required for # TeamServer to process the JSON form of this message. # # @return [Hash] # @raise [ArgumentError] def to_controlled_hash validate { components: components.map(&:to_controlled_hash), libraries: libraries.map(&:to_controlled_hash), timestamp: timestamp } end # Ensure the required fields are present. # # @raise [ArgumentError] def validate; end private # The timestamp field is a bit of a misnomer. It's really the time, in ms, since the settings for this # application have been updated. # # @return [Integer] def timestamp Contrast::Utils::Timer.now_ms - (Contrast::Agent.reporter&.client&.response_handler&.last_app_update_ms || 0) end end end end end