Skip to content

Commit dd33b44

Browse files
authored
Make RC proxy filter products like the proper agent (#7175)
1 parent 321448b commit dd33b44

2 files changed

Lines changed: 47 additions & 3 deletions

File tree

manifests/ruby.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2392,7 +2392,7 @@ manifest:
23922392
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationExtraServices: missing_feature
23932393
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceASMDD: v1.13.0
23942394
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceASMDDNoCache: missing_feature
2395-
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceFeatures: v1.13.0
2395+
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceFeatures: missing_feature
23962396
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceFeaturesNoCache: missing_feature
23972397
tests/remote_config/test_remote_configuration.py::Test_RemoteConfigurationUpdateSequenceLiveDebugging: v1.13.0
23982398
tests/serverless/span_pointers/aws/test_s3_span_pointers.py::Test_CopyObject: missing_feature

utils/proxy/mocked_response.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,42 @@ def send(self) -> None:
160160
"""Send instruction to the proxy at /mocked_tracer_responses endpoint."""
161161
self._send_to_endpoint(MOCKED_TRACER_RESPONSES_PATH)
162162

163+
@staticmethod
164+
def _gate_rc_response_by_products(response: dict, request_content: dict) -> dict:
165+
"""Restrict a /v0.7/config response to the products the client subscribed to.
166+
167+
The real Datadog agent only returns configs for products listed in the
168+
request's ``client.products``. Mirror the real-world behaviour here.
169+
"""
170+
if not isinstance(response, dict):
171+
return response
172+
client_configs = response.get("client_configs")
173+
if not isinstance(client_configs, list):
174+
return response
175+
try:
176+
products = request_content["client"]["products"]
177+
except (KeyError, TypeError):
178+
return response
179+
if not isinstance(products, list):
180+
return response
181+
allowed = set(products)
182+
183+
def product_of(path: str) -> str | None:
184+
# datadog/<org_id>/<PRODUCT>/<config_id>/<name> or employee/<PRODUCT>/<config_id>/<name>
185+
parts = path.split("/")
186+
return parts[-3]
187+
188+
kept = [path for path in client_configs if product_of(path) in allowed]
189+
if kept == client_configs:
190+
return response
191+
filtered = dict(response)
192+
filtered["client_configs"] = kept
193+
target_files = response.get("target_files")
194+
if isinstance(target_files, list):
195+
kept_paths = set(kept)
196+
filtered["target_files"] = [tf for tf in target_files if tf.get("path") in kept_paths]
197+
return filtered
198+
163199

164200
class StaticJsonMockedTracerResponse(MockedTracerResponse):
165201
"""Always overwrites the same static JSON content on request made on the given path."""
@@ -175,7 +211,15 @@ def _apply_status_code(self, flow: HTTPFlow) -> None:
175211

176212
def execute(self, flow: HTTPFlow) -> None:
177213
super().execute(flow)
178-
flow.response.content = json.dumps(self.mocked_json).encode()
214+
response = self.mocked_json
215+
if self.path == "/v0.7/config" and isinstance(response, dict):
216+
try:
217+
request_content = json.loads(flow.request.content)
218+
except (ValueError, TypeError):
219+
request_content = None
220+
if isinstance(request_content, dict):
221+
response = self._gate_rc_response_by_products(response, request_content)
222+
flow.response.content = json.dumps(response).encode()
179223

180224
def to_json(self) -> dict:
181225
return {
@@ -203,7 +247,7 @@ def execute(self, flow: HTTPFlow) -> None:
203247
request_content = json.loads(flow.request.content)
204248
runtime_id = request_content["client"]["client_tracer"]["runtime_id"]
205249
nth_api_command = self._runtime_ids_request_count[runtime_id]
206-
response = self.mocked_json_sequence[nth_api_command]
250+
response = self._gate_rc_response_by_products(self.mocked_json_sequence[nth_api_command], request_content)
207251

208252
flow.response.content = json.dumps(response).encode()
209253
flow.response.headers["st-proxy-overwrite-rc-response"] = f"{nth_api_command}"

0 commit comments

Comments
 (0)