Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Steepfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ target :datadog do
# * `:information`, `:hint`: To see these, run `rake 'typecheck[--severity-level=information]'`
# or `rake 'typecheck[--severity-level=hint]'`

# These first checks are likely the easiest to fix, given they capture a mismatch
# between the already declared type in `.rbs` and the actual type inferred by Steep.
hash[Ruby::IncompatibleAssignment] = :information

# These checks are a bit harder, because they represent the lack of sufficient type information.
hash[Ruby::FallbackAny] = :information
hash[Ruby::UnknownInstanceVariable] = :information
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/appsec/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ module AppSec
# This class accumulates the context over the request life-cycle and exposes
# interface sufficient for instrumentation to perform threat detection.
class Context
ActiveContextError = Class.new(StandardError)
# Steep: https://github.com/soutaro/steep/issues/1880
ActiveContextError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use class ActiveContextError < StandardError does steep then work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does but I remember that @Strech preferred to keep it as is, which is why I've added a comment with the issue, and disabled it

Copy link
Member

@Strech Strech Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think type definition as such should work, no? But code could stay the same


# TODO: add delegators for active trace span
attr_reader :trace, :span, :events
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/appsec/security_engine/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class Error

def initialize(duration_ext_ns:, input_truncated:)
@events = []
@actions = @attributes = {}
@actions = {}
@attributes = {}
Comment on lines 71 to +74
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to do a double-take on this one -- this is not exactly the same as before but in practice these classes are never mutated.

@y9v, @Strech may not be a bad idea to spray a few .freeze calls around here to make it even more obvious this is all supposed to be immutable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spot on, indeed a freeze makes sense here

@duration_ns = 0
@duration_ext_ns = duration_ext_ns
@input_truncated = !!input_truncated
Expand Down
6 changes: 4 additions & 2 deletions lib/datadog/core/configuration/option_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def build(context)
# Acts as DSL for building OptionDefinitions
# @public_api
class Builder
InvalidOptionError = Class.new(StandardError)
# Steep: https://github.com/soutaro/steep/issues/1880
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but will this work?

class InvalidOptionError < StandardError
end


attr_reader \
:helpers
Expand Down Expand Up @@ -119,7 +120,8 @@ def apply_options!(options = {})
env_parser(&options[:env_parser]) if options.key?(:env_parser)
after_set(&options[:after_set]) if options.key?(:after_set)
resetter(&options[:resetter]) if options.key?(:resetter)
setter(&options[:setter]) if options.key?(:setter)
# Steep: https://github.com/soutaro/steep/issues/477
setter(&options[:setter]) if options.key?(:setter) # steep:ignore BlockTypeMismatch
type(options[:type], **(options[:type_options] || {})) if options.key?(:type)
end

Expand Down
13 changes: 8 additions & 5 deletions lib/datadog/core/configuration/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ def option(name, meta = {}, &block)

def default_helpers(name)
option_name = name.to_sym
# @type var opt_getter: Configuration::OptionDefinition::helper_proc
opt_getter = proc do
# Steep: https://github.com/soutaro/steep/issues/335
# @type var opt_getter: Configuration::OptionDefinition::generic_proc
opt_getter = proc do # steep:ignore IncompatibleAssignment
# These Procs uses `get/set_option`, but we only add them to the OptionDefinition helpers here.
# Steep is right that these methods are not defined, but we only run these Procs in instance context.
get_option(option_name) # steep:ignore NoMethod
end
# @type var opt_setter: Configuration::OptionDefinition::helper_proc
opt_setter = proc do |value|
# Steep: https://github.com/soutaro/steep/issues/335
# @type var opt_setter: Configuration::OptionDefinition::generic_proc
opt_setter = proc do |value| # steep:ignore IncompatibleAssignment
set_option(option_name, value) # steep:ignore NoMethod
end
{
Expand Down Expand Up @@ -127,7 +129,8 @@ def assert_valid_option!(name)
end
end

InvalidOptionError = Class.new(StandardError)
# Steep: https://github.com/soutaro/steep/issues/1880
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
end
end
end
Expand Down
10 changes: 9 additions & 1 deletion lib/datadog/core/rate_limiter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ def effective_rate

return current_window_rate if @prev_conforming_messages.nil? || @prev_total_messages.nil?

# Steep: Due to https://github.com/soutaro/steep/issues/477,
# the previous nil check does not narrow type to Integer
# The annotation fixes the typing error, but it takes effect in the method
# @type ivar @prev_total_messages: Integer
(@conforming_messages.to_f + @prev_conforming_messages.to_f) / (@total_messages + @prev_total_messages)
end

Expand Down Expand Up @@ -154,7 +158,11 @@ def update_rate_counts(allowed)
if @current_window.nil?
@current_window = now
# If more than 1 second has past since last window, reset
elsif now - @current_window >= 1
#
# Steep: @current_window is a Float, but for some reason annotations does not work here
# Once a fix will be out for nil checks on instance variables, we can remove the steep:ignore
# https://github.com/soutaro/steep/issues/477
elsif now - @current_window >= 1 # steep:ignore UnresolvedOverloading
@prev_conforming_messages = @conforming_messages
@prev_total_messages = @total_messages
@conforming_messages = 0
Expand Down
2 changes: 1 addition & 1 deletion lib/datadog/core/utils/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Time
# Current monotonic time
#
# @param unit [Symbol] unit for the resulting value, same as ::Process#clock_gettime, defaults to :float_second
# @return [Numeric] timestamp in the requested unit, since some unspecified starting point
# @return [Float|Integer] timestamp in the requested unit, since some unspecified starting point
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

def get_time(unit = :float_second)
Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
end
Expand Down
12 changes: 8 additions & 4 deletions lib/datadog/di/el/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ def compile(ast)

private

OPERATORS = {
# Steep: https://github.com/soutaro/steep/issues/363
OPERATORS = { # steep:ignore IncompatibleAssignment
'eq' => '==',
'ne' => '!=',
'ge' => '>=',
Expand All @@ -31,16 +32,19 @@ def compile(ast)
'lt' => '<',
}.freeze

# Steep: https://github.com/soutaro/steep/issues/363
SINGLE_ARG_METHODS = %w[
len isEmpty isUndefined
].freeze
].freeze # steep:ignore IncompatibleAssignment

# Steep: https://github.com/soutaro/steep/issues/363
TWO_ARG_METHODS = %w[
startsWith endsWith contains matches
getmember index instanceof
].freeze
].freeze # steep:ignore IncompatibleAssignment

MULTI_ARG_METHODS = {
# Steep: https://github.com/soutaro/steep/issues/363
MULTI_ARG_METHODS = { # steep:ignore IncompatibleAssignment
'and' => '&&',
'or' => '||',
}.freeze
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/di/probe_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ module DI
#
# @api private
module ProbeBuilder
PROBE_TYPES = {
# Steep: https://github.com/soutaro/steep/issues/363
PROBE_TYPES = { # steep:ignore IncompatibleAssignment
'LOG_PROBE' => :log,
}.freeze

Expand Down
2 changes: 1 addition & 1 deletion lib/datadog/di/probe_notification_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def build_executed(context)
build_snapshot(context)
end

NANOSECONDS = 10**9
NANOSECONDS = 1_000_000_000
MILLISECONDS = 1000

def build_snapshot(context)
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/profiling/collectors/code_provenance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ def initialize(kind:, name:, version:, path:, extra_paths:)
end

def to_json(arg = nil)
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
# Steep: https://github.com/ruby/rbs/pull/2691
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg) # steep:ignore ArgumentTypeMismatch
end

def path
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/profiling/collectors/info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module Collectors
class Info
def initialize(settings)
@profiler_info = nil
@info = {
# Steep: https://github.com/soutaro/steep/issues/363
@info = { # steep:ignore IncompatibleAssignment
platform: collect_platform_info,
runtime: collect_runtime_info,
application: collect_application_info(settings),
Expand Down
5 changes: 4 additions & 1 deletion lib/datadog/profiling/http_transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ class HttpTransport
def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:)
@upload_timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i

@exporter_configuration =
# Steep: multiple issues here
# first https://github.com/soutaro/steep/issues/363
# then https://github.com/soutaro/steep/issues/1603 (remove the .freeze to see it)
@exporter_configuration = # steep:ignore IncompatibleAssignment
if agentless?(site, api_key)
[:agentless, site, api_key].freeze
else
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/tracing/contrib/status_range_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class StatusRangeMatcher
attr_reader :ranges

def initialize(ranges)
@ranges = Array(ranges)
# Steep: https://github.com/ruby/rbs/issues/1874
@ranges = Array(ranges) # steep:ignore IncompatibleAssignment
end

def +(other)
Expand Down
4 changes: 3 additions & 1 deletion lib/datadog/tracing/contrib/utils/quantization/hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ module Hash
PLACEHOLDER = '?'
EXCLUDE_KEYS = [].freeze
SHOW_KEYS = [].freeze
DEFAULT_OPTIONS = {

# Steep: https://github.com/soutaro/steep/issues/363
DEFAULT_OPTIONS = { # steep:ignore IncompatibleAssignment
exclude: EXCLUDE_KEYS,
show: SHOW_KEYS,
placeholder: PLACEHOLDER
Expand Down
4 changes: 2 additions & 2 deletions lib/datadog/tracing/span_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ def to_native_format

private

MIN_INT64_SIGNED = -2**63
MAX_INT64_SIGNED = 2 << 63 - 1
MIN_INT64_SIGNED = -2 << 62
MAX_INT64_SIGNED = (2 << 62) - 1

# Checks the attributes hash to ensure it only contains serializable values.
# Invalid values are removed from the hash.
Expand Down
13 changes: 9 additions & 4 deletions lib/datadog/tracing/span_operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ def finished?
def duration
return @duration_end - @duration_start if @duration_start && @duration_end

@end_time - @start_time if @start_time && @end_time
# Steep: https://github.com/soutaro/steep/issues/477
@end_time - @start_time if @start_time && @end_time # steep:ignore NoMethod
end

def set_error(e)
Expand Down Expand Up @@ -387,15 +388,16 @@ def pretty_print(q)
class Events
include Tracing::Events

DEFAULT_ON_ERROR = proc { |span_op, error| span_op&.set_error(error) }
# Steep: https://github.com/soutaro/steep/issues/335
DEFAULT_ON_ERROR = proc { |span_op, error| span_op&.set_error(error) } # steep:ignore IncompatibleAssignment

attr_reader \
:logger,
:after_finish,
:after_stop,
:before_start

def initialize(logger: Datadog.logger, on_error: nil)
def initialize(logger: Datadog.logger)
@logger = logger
@after_finish = AfterFinish.new
@after_stop = AfterStop.new
Expand Down Expand Up @@ -548,7 +550,10 @@ def duration_marker
# Used for serialization
# @return [Integer] in nanoseconds since Epoch
def start_time_nano
@start_time.to_i * 1000000000 + @start_time.nsec
return 0 if @start_time.nil?

# Steep: https://github.com/soutaro/steep/issues/477
@start_time.to_i * 1000000000 + @start_time.nsec # steep:ignore NoMethod
end

# Used for serialization
Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/appsec/context.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Datadog

@interrupted: bool

ActiveContextError: ::StandardError
ActiveContextError: StandardError

attr_reader trace: Tracing::TraceOperation

Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/appsec/metrics/collector.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Datadog

attr_accessor inputs_truncated: ::Integer

def self.new: (evals: ::Integer, matches: ::Integer, errors: ::Integer, timeouts: ::Integer, duration_ns: ::Integer, duration_ext_ns: ::Integer, inputs_truncated: ::Integer) -> void
def self.new: (evals: ::Integer, matches: ::Integer, errors: ::Integer, timeouts: ::Integer, duration_ns: ::Integer, duration_ext_ns: ::Integer, inputs_truncated: ::Integer) -> Store
end

@mutex: Mutex
Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/appsec/security_engine/engine.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Datadog

@ruleset_version: ::String

@reconfigured_ruleset_version: ::String?
@reconfigured_ruleset_version: ::String

DEFAULT_RULES_CONFIG_PATH: ::String
TELEMETRY_ACTIONS: ::Array[::String]
Expand Down
46 changes: 29 additions & 17 deletions sig/datadog/core/configuration/option_definition.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,39 @@ module Datadog
class OptionDefinition
type option_type = String | Integer | Float | Rational | Symbol | bool | Array[untyped] | Hash[untyped, untyped] | nil

type option_proc = (^(Options::GenericSettingsClass _settings) [self: Options::GenericSettingsClass] -> option_type)
type option_proc = (^(Options::GenericSettingsClass settings) [self: Options::GenericSettingsClass] -> option_type)

type helper_proc = (^(?) [self: Options::GenericSettingsClass] -> untyped)
type generic_proc = (^(?) [self: Options::GenericSettingsClass] -> untyped)

type meta = {
default: (option_type | option_proc | Options::GenericSettingsClass)?,
default_proc: option_proc?,
env: String?,
env_parser: (^(String env_value) [self: Options::GenericSettingsClass] -> Option::env_value)?,
after_set: (^(option_type value, option_type old_value, Option::Precedence::Value precedence) [self: Options::GenericSettingsClass] -> void)?,
resetter: (^(option_type value) [self: Options::GenericSettingsClass] -> option_type)?,
setter: (^(option_type new_value, option_type old_value) [self: Options::GenericSettingsClass] -> option_type),
type: Symbol?,
?default: (option_type | option_proc | Options::GenericSettingsClass)?,
?default_proc: generic_proc?,
?env: String?,
?env_parser: (^(String env_value) [self: Options::GenericSettingsClass] -> Option::env_value)?,
?after_set: (^(option_type value, option_type old_value, Option::Precedence::Value precedence) [self: Options::GenericSettingsClass] -> void)?,
?resetter: (^(option_type value) [self: Options::GenericSettingsClass] -> option_type)?,
?setter: (^(option_type new_value, option_type old_value) [self: Options::GenericSettingsClass] -> option_type)?,
?type: Symbol?,
?type_options: Hash[Symbol, untyped]
}

type meta_with_type_options = {
?default: (option_type | option_proc | Options::GenericSettingsClass)?,
?default_proc: generic_proc?,
?env: String?,
?env_parser: (^(String env_value) [self: Options::GenericSettingsClass] -> Option::env_value)?,
?after_set: (^(option_type value, option_type old_value, Option::Precedence::Value precedence) [self: Options::GenericSettingsClass] -> void)?,
?resetter: (^(option_type value) [self: Options::GenericSettingsClass] -> option_type)?,
?setter: (^(option_type new_value, option_type old_value) [self: Options::GenericSettingsClass] -> option_type)?,
?type: Symbol?,
type_options: Hash[Symbol, untyped]
}

IDENTITY: ^(option_type new_value, option_type _old_value) [self: Options::GenericSettingsClass] -> option_type

attr_reader default: option_type | option_proc | Options::GenericSettingsClass

attr_reader default_proc: option_proc?
attr_reader default_proc: generic_proc?

attr_reader env: String?

Expand All @@ -42,21 +54,21 @@ module Datadog

attr_reader type_options: Hash[Symbol, untyped]

def initialize: (String | Symbol name, meta meta) ?{ (option_type new_value, option_type old_value) [self: Options::GenericSettingsClass] -> option_type } -> void
def initialize: (String | Symbol name, meta_with_type_options meta) ?{ (option_type new_value, option_type old_value) [self: Options::GenericSettingsClass] -> option_type } -> void

def build: (Options::GenericSettingsClass context) -> Option

class Builder
class InvalidOptionError < StandardError
end

attr_reader helpers: Hash[Symbol, helper_proc]
attr_reader helpers: Hash[Symbol, generic_proc]

@env: String?
@env_parser: (^(String env_value) [self: Options::GenericSettingsClass] -> Option::env_value)?
@default: option_type | option_proc | Options::GenericSettingsClass
@default_proc: option_proc?
@helpers: Hash[Symbol, helper_proc]
@default_proc: generic_proc?
@helpers: Hash[Symbol, generic_proc]
@name: Symbol
@after_set: (^(option_type value, option_type old_value, Option::Precedence::Value precedence) [self: Options::GenericSettingsClass] -> void)?
@resetter: (^(option_type value) [self: Options::GenericSettingsClass] -> option_type)?
Expand All @@ -71,9 +83,9 @@ module Datadog
def env_parser: () ?{ (String env_value) [self: Options::GenericSettingsClass] -> Option::env_value } -> void

# can also be a class that includes Configuration::Base for new settings
def default: (?(option_type | option_proc | Options::GenericSettingsClass) value) ?{ () -> (option_type | option_proc | Options::GenericSettingsClass) } -> void
def default: (?(option_type | option_proc | Options::GenericSettingsClass) value) ?{ (Options::GenericSettingsClass settings) [self: Options::GenericSettingsClass] -> option_type } -> void

def default_proc: () ?{ (Options::GenericSettingsClass _settings) [self: Options::GenericSettingsClass] -> option_type } -> void
def default_proc: () ?{ (?) [self: Options::GenericSettingsClass] -> untyped } -> void

def type: (Symbol? value, ?nilable: bool) -> void

Expand Down
4 changes: 2 additions & 2 deletions sig/datadog/core/configuration/options.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ module Datadog

private

def default_helpers: (Symbol | String name) -> Hash[Symbol, OptionDefinition::helper_proc]
def default_helpers: (Symbol | String name) -> Hash[Symbol, OptionDefinition::generic_proc]

def define_helpers: (Hash[Symbol, OptionDefinition::helper_proc] helpers) -> void
def define_helpers: (Hash[Symbol, OptionDefinition::generic_proc] helpers) -> void

# Fake methods to make it work with RBS. RBS cannot understand that this module is only used in a class context.
def superclass: () -> singleton(Options)
Expand Down
Loading
Loading