Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEBUG-2334 Ruby DI system tests #3516

Merged
merged 3 commits into from
Nov 21, 2024
Merged
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
18 changes: 18 additions & 0 deletions tests/debugger/probes/pii_line.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"language": "",
"pii": "",
"id": "log170aa-acda-4453-9111-1478a600line",
"where": {
"typeName": null,
"sourceFile": "ACTUAL_SOURCE_FILE",
"lines": [
"33"
]
},
"captureSnapshot": true,
"capture": {
"maxFieldCount": 200
}
}
]
52 changes: 37 additions & 15 deletions tests/debugger/test_debugger_pii.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,35 +121,38 @@ def filter(keys_to_filter):
@features.debugger_pii_redaction
@scenarios.debugger_pii_redaction
class Test_Debugger_PII_Redaction(base._Base_Debugger_Test):
def _setup(self):
probes = base.read_probes("pii")
def _setup(self, probes_file):
probes = base.read_probes(probes_file)
self.expected_probe_ids = base.extract_probe_ids(probes)
self.rc_state = rc.send_debugger_command(probes, version=1)

interfaces.agent.wait_for(self.wait_for_all_probes_installed, timeout=30)

self.weblog_responses = [weblog.get("/debugger/pii")]

def _test(self, redacted_keys, redacted_types):
def _test(self, redacted_keys, redacted_types, line_probe=False):
self.assert_all_states_not_error()
self.assert_all_probes_are_installed()
self.assert_all_weblog_responses_ok()

self._validate_pii_keyword_redaction(redacted_keys)
self._validate_pii_type_redaction(redacted_types)
self._validate_pii_keyword_redaction(redacted_keys, line_probe=line_probe)
self._validate_pii_type_redaction(redacted_types, line_probe=line_probe)

def setup_pii_redaction_full(self):
self._setup()
self._setup("pii")

@missing_feature(context.library < "[email protected]", reason="keywords are not fully redacted")
@missing_feature(context.library < "[email protected]", reason="keywords are not fully redacted")
@bug(context.library == "[email protected]", reason="DEBUG-3127")
@bug(context.library == "[email protected]", reason="DEBUG-3127")
# Ruby requires @irrelevant rather than @missing_feature to skip setup
# for this test (which will interfere with the line probe test).
@irrelevant(context.library == "ruby", reason="Local variable capture not implemented for method probes")
def test_pii_redaction_full(self):
self._test(REDACTED_KEYS, REDACTED_TYPES)

def setup_pii_redaction_java_1_33(self):
self._setup()
self._setup("pii")

@irrelevant(context.library != "[email protected]", reason="not relevant for other version")
def test_pii_redaction_java_1_33(self):
Expand All @@ -170,7 +173,7 @@ def test_pii_redaction_java_1_33(self):
)

def setup_pii_redaction_dotnet_2_50(self):
self._setup()
self._setup("pii")

@irrelevant(context.library != "[email protected]", reason="not relevant for other version")
@bug(
Expand All @@ -179,7 +182,14 @@ def setup_pii_redaction_dotnet_2_50(self):
def test_pii_redaction_dotnet_2_50(self):
self._test(filter(["applicationkey", "connectionstring"]), REDACTED_TYPES)

def _validate_pii_keyword_redaction(self, should_redact_field_names):
def setup_pii_redaction_line(self):
self._setup("pii_line")

@irrelevant(context.library != "ruby", reason="Ruby needs to use line probes to capture variables")
def test_pii_redaction_line(self):
self._test(REDACTED_KEYS, REDACTED_TYPES, True)

def _validate_pii_keyword_redaction(self, should_redact_field_names, line_probe=False):
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v2/logs"))
not_redacted = []
not_found = list(set(should_redact_field_names))
Expand All @@ -193,12 +203,21 @@ def _validate_pii_keyword_redaction(self, should_redact_field_names):

if snapshot:
for field_name in should_redact_field_names:
fields = snapshot["captures"]["return"]["locals"]["pii"]["fields"]

if field_name in fields:
if line_probe:
fields = snapshot["captures"]["lines"]["33"]["locals"]["pii"]["fields"]
else:
fields = snapshot["captures"]["return"]["locals"]["pii"]["fields"]

# Ruby prefixes instance variable names with @
if context.library == "ruby":
check_field_name = "@" + field_name
else:
check_field_name = field_name

if check_field_name in fields:
not_found.remove(field_name)

if "value" in fields[field_name]:
if "value" in fields[check_field_name]:
not_redacted.append(field_name)
error_message = ""
if not_redacted:
Expand All @@ -212,7 +231,7 @@ def _validate_pii_keyword_redaction(self, should_redact_field_names):
if error_message != "":
raise ValueError(error_message)

def _validate_pii_type_redaction(self, should_redact_types):
def _validate_pii_type_redaction(self, should_redact_types, line_probe=False):
agent_logs_endpoint_requests = list(interfaces.agent.get_data(path_filters="/api/v2/logs"))
not_redacted = []

Expand All @@ -225,7 +244,10 @@ def _validate_pii_type_redaction(self, should_redact_types):

if snapshot:
for type_name in should_redact_types:
type_info = snapshot["captures"]["return"]["locals"][type_name]
if line_probe:
type_info = snapshot["captures"]["lines"]["33"]["locals"][type_name]
else:
type_info = snapshot["captures"]["return"]["locals"][type_name]

if "fields" in type_info:
not_redacted.append(type_name)
Expand Down
5 changes: 4 additions & 1 deletion tests/debugger/test_debugger_probe_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import tests.debugger.utils as base

from utils import scenarios, interfaces, weblog, features, remote_config as rc, bug
from utils import scenarios, interfaces, weblog, features, remote_config as rc, bug, missing_feature, context


@features.debugger
Expand Down Expand Up @@ -41,6 +41,7 @@ def setup_span_method_probe_snaphots(self):
]

@bug(library="python", reason="DEBUG-2708, DEBUG-2709")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_span_method_probe_snaphots(self):
self.assert_all_states_not_error()
self.assert_all_probes_are_installed()
Expand All @@ -61,6 +62,7 @@ def setup_span_decoration_method_probe_snaphots(self):
]

@bug(library="python", reason="DEBUG-2708, DEBUG-2709")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_span_decoration_method_probe_snaphots(self):
self.assert_all_states_not_error()
self.assert_all_probes_are_installed()
Expand Down Expand Up @@ -105,6 +107,7 @@ def setup_span_decoration_line_probe_snaphots(self):
weblog.get("/debugger/span-decoration/asd/1"),
]

@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_span_decoration_line_probe_snaphots(self):
self.assert_all_states_not_error()
self.assert_all_probes_are_installed()
Expand Down
5 changes: 4 additions & 1 deletion tests/debugger/test_debugger_probe_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import tests.debugger.utils as base

from utils import scenarios, features, remote_config as rc, bug, context
from utils import weblog, scenarios, features, remote_config as rc, bug, context, missing_feature


@features.debugger
Expand Down Expand Up @@ -40,6 +40,7 @@ def setup_probe_status_metric(self):

@bug(context.library == "[email protected]", reason="DEBUG-3127")
@bug(context.library == "[email protected]", reason="DEBUG-3127")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_probe_status_metric(self):
self._assert()

Expand All @@ -49,6 +50,7 @@ def setup_probe_status_span(self):

self._setup(probes)

@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_probe_status_span(self):
self._assert()

Expand All @@ -60,6 +62,7 @@ def setup_probe_status_spandecoration(self):

@bug(context.library == "[email protected]", reason="DEBUG-3127")
@bug(context.library == "[email protected]", reason="DEBUG-3127")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_probe_status_spandecoration(self):
self._assert()

Expand Down
12 changes: 7 additions & 5 deletions tests/debugger/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from utils.dd_constants import RemoteConfigApplyState as ApplyState

_CONFIG_PATH = "/v0.7/config"
_DEBUGER_PATH = "/api/v2/debugger"
_DEBUGGER_PATH = "/api/v2/debugger"
_LOGS_PATH = "/api/v2/logs"
_TRACES_PATH = "/api/v0.2/traces"

Expand Down Expand Up @@ -51,16 +51,18 @@ def read_diagnostic_data():
tracer_version = version.parse(re.sub(r"[^0-9.].*$", "", tracer["tracer_version"]))
if tracer["language"] == "java":
if tracer_version > version.parse("1.27.0"):
path = _DEBUGER_PATH
path = _DEBUGGER_PATH
else:
path = _LOGS_PATH
elif tracer["language"] == "dotnet":
if tracer_version > version.parse("2.49.0"):
path = _DEBUGER_PATH
path = _DEBUGGER_PATH
else:
path = _LOGS_PATH
elif tracer["language"] == "python":
path = _DEBUGER_PATH
path = _DEBUGGER_PATH
elif tracer["language"] == "ruby":
path = _DEBUGGER_PATH
else:
path = _LOGS_PATH

Expand Down Expand Up @@ -133,7 +135,7 @@ def _all_probes_installed(self, probes_map):
return False

if not self.all_probes_installed:
if data["path"] == _DEBUGER_PATH or data["path"] == _LOGS_PATH:
if data["path"] == _DEBUGGER_PATH or data["path"] == _LOGS_PATH:
self.all_probes_installed = _all_probes_installed(self, get_probes_map([data]))

return self.all_probes_installed
Expand Down
7 changes: 7 additions & 0 deletions utils/_remote_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,20 @@ def _get_probe_type(probe_id):
probe["where"]["methodName"] = re.sub(
r"([a-z])([A-Z])", r"\1_\2", probe["where"]["methodName"]
).lower()
elif library_name == "ruby":
probe["where"]["typeName"] = "DebuggerController"
probe["where"]["methodName"] = re.sub(
r"([a-z])([A-Z])", r"\1_\2", probe["where"]["methodName"]
).lower()
elif probe["where"]["sourceFile"] == "ACTUAL_SOURCE_FILE":
if library_name == "dotnet":
probe["where"]["sourceFile"] = "DebuggerController.cs"
elif library_name == "java":
probe["where"]["sourceFile"] = "DebuggerController.java"
elif library_name == "python":
probe["where"]["sourceFile"] = "debugger_controller.py"
elif library_name == "ruby":
probe["where"]["sourceFile"] = "debugger_controller.rb"

logger.debug(f"RC probe is:\n{json.dumps(probe, indent=2)}")
probe_type = _get_probe_type(probe["id"])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Padding
# Padding
# Padding
# Padding

class DebuggerController < ActionController::Base
def init
# This method does nothing.
# When the endpoint corresponding to it is invoked however,
# the middleware installed by dd-trace-rb initializes remote configuration.
render inline: 'debugger init'
end

# Padding
# Padding
# Padding
# Padding

def log_probe
render inline: 'Log probe' # This needs to be line 20
end

# Padding
# Padding
# Padding
# Padding

def pii
pii = Pii.new
customPii = CustomPii.new
value = pii.test_value
custom_value = customPii.test_value
render inline: "PII #{value}. CustomPII #{custom_value}" # must be line 33
end

# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding
# Padding

def mix_probe
value = params[:string_arg].length * Integer(params[:int_arg])
render inline: "Mixed result #{value}" # must be line 52
end
end
7 changes: 7 additions & 0 deletions utils/build/docker/ruby/rails70/app/models/base_pii.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class BasePii
def initialize
@test_value = 'should be redacted'
end

attr_reader :test_value
end
5 changes: 5 additions & 0 deletions utils/build/docker/ruby/rails70/app/models/custom_pii.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CustomPii < BasePii
def initialize
@custom_key = 'should be redacted'
end
end
Loading
Loading