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
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
@@ -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 < "java@1.34", reason="keywords are not fully redacted")
@missing_feature(context.library < "dotnet@2.51", reason="keywords are not fully redacted")
@bug(context.library == "python@2.16.0", reason="DEBUG-3127")
@bug(context.library == "python@2.16.1", 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 != "java@1.33", reason="not relevant for other version")
def test_pii_redaction_java_1_33(self):
@@ -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 != "dotnet@2.50", reason="not relevant for other version")
@bug(
@@ -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))
@@ -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:
@@ -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 = []

@@ -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)
5 changes: 4 additions & 1 deletion tests/debugger/test_debugger_probe_snapshot.py
Original file line number Diff line number Diff line change
@@ -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
@@ -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()
@@ -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()
@@ -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()
5 changes: 4 additions & 1 deletion tests/debugger/test_debugger_probe_status.py
Original file line number Diff line number Diff line change
@@ -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
@@ -40,6 +40,7 @@ def setup_probe_status_metric(self):

@bug(context.library == "python@2.16.0", reason="DEBUG-3127")
@bug(context.library == "python@2.16.1", reason="DEBUG-3127")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_probe_status_metric(self):
self._assert()

@@ -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()

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

@bug(context.library == "python@2.16.0", reason="DEBUG-3127")
@bug(context.library == "python@2.16.1", reason="DEBUG-3127")
@missing_feature(context.library == "ruby", reason="Not yet implemented")
def test_probe_status_spandecoration(self):
self._assert()

12 changes: 7 additions & 5 deletions tests/debugger/utils.py
Original file line number Diff line number Diff line change
@@ -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"

@@ -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

@@ -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
7 changes: 7 additions & 0 deletions utils/_remote_config.py
Original file line number Diff line number Diff line change
@@ -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"])
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