diff --git a/tests/appsec/iast/sink/test_command_injection.py b/tests/appsec/iast/sink/test_command_injection.py
index 5f3a3202f73..e97d091f3a5 100644
--- a/tests/appsec/iast/sink/test_command_injection.py
+++ b/tests/appsec/iast/sink/test_command_injection.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, missing_feature
+from utils import context, coverage, missing_feature, features
from .._test_iast_fixtures import BaseSinkTest
+@features.iast_sink_command_injection
@coverage.basic
class TestCommandInjection(BaseSinkTest):
"""Test command injection detection."""
diff --git a/tests/appsec/iast/sink/test_hardcoded_secrets.py b/tests/appsec/iast/sink/test_hardcoded_secrets.py
index bc1ed3a8421..5a3b9004e19 100644
--- a/tests/appsec/iast/sink/test_hardcoded_secrets.py
+++ b/tests/appsec/iast/sink/test_hardcoded_secrets.py
@@ -2,11 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import flaky, context, coverage, missing_feature
-from utils.tools import logging
+from utils import coverage, missing_feature, features
from .._test_iast_fixtures import BaseSinkTest, DetectionStage
+@features.iast_sink_hardcoded_secrets
@coverage.basic
class Test_HardcodedSecrets(BaseSinkTest):
"""Test Hardcoded secrets detection."""
diff --git a/tests/appsec/iast/sink/test_ldap_injection.py b/tests/appsec/iast/sink/test_ldap_injection.py
index c3eefd34679..4216df42bd2 100644
--- a/tests/appsec/iast/sink/test_ldap_injection.py
+++ b/tests/appsec/iast/sink/test_ldap_injection.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, missing_feature
+from utils import context, coverage, missing_feature, features
from .._test_iast_fixtures import BaseSinkTest
+@features.iast_sink_ldap_injection
@coverage.basic
class TestLDAPInjection(BaseSinkTest):
"""Test LDAP injection detection."""
diff --git a/tests/appsec/iast/sink/test_path_traversal.py b/tests/appsec/iast/sink/test_path_traversal.py
index 58caa851053..6a1813bfbf7 100644
--- a/tests/appsec/iast/sink/test_path_traversal.py
+++ b/tests/appsec/iast/sink/test_path_traversal.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, missing_feature
+from utils import context, coverage, missing_feature, features
from .._test_iast_fixtures import BaseSinkTest
@coverage.basic
+@features.iast_sink_path_traversal
class TestPathTraversal(BaseSinkTest):
"""Test path traversal detection."""
diff --git a/tests/appsec/iast/sink/test_sql_injection.py b/tests/appsec/iast/sink/test_sql_injection.py
index 603b5b3f24a..f9499f0621b 100644
--- a/tests/appsec/iast/sink/test_sql_injection.py
+++ b/tests/appsec/iast/sink/test_sql_injection.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, missing_feature
+from utils import context, coverage, missing_feature, features
from .._test_iast_fixtures import BaseSinkTest
@coverage.basic
+@features.iast_sink_sql_injection
class TestSqlInjection(BaseSinkTest):
"""Verify SQL injection detection."""
diff --git a/tests/appsec/iast/sink/test_weak_cipher.py b/tests/appsec/iast/sink/test_weak_cipher.py
index 86f6ca5e9e4..3c5f73dacb2 100644
--- a/tests/appsec/iast/sink/test_weak_cipher.py
+++ b/tests/appsec/iast/sink/test_weak_cipher.py
@@ -1,11 +1,12 @@
# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, missing_feature, coverage, flaky
+from utils import context, missing_feature, coverage, flaky, features
from .._test_iast_fixtures import BaseSinkTest
@coverage.basic
+@features.weak_cipher_detection
class TestWeakCipher(BaseSinkTest):
"""Verify weak cipher detection."""
diff --git a/tests/appsec/iast/sink/test_weak_hash.py b/tests/appsec/iast/sink/test_weak_hash.py
index 2afbdb2e17a..e79993ff844 100644
--- a/tests/appsec/iast/sink/test_weak_hash.py
+++ b/tests/appsec/iast/sink/test_weak_hash.py
@@ -2,7 +2,7 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import weblog, context, bug, missing_feature, coverage
+from utils import weblog, context, bug, missing_feature, coverage, features
from .._test_iast_fixtures import BaseSinkTest, assert_iast_vulnerability
@@ -32,6 +32,7 @@ def _expected_evidence():
@coverage.basic
+@features.weak_hash_vulnerability_detection
class TestWeakHash(BaseSinkTest):
"""Verify weak hash detection."""
diff --git a/tests/appsec/iast/source/test_body.py b/tests/appsec/iast/source/test_body.py
index b5dd795ff90..2fc03ef10b1 100644
--- a/tests/appsec/iast/source/test_body.py
+++ b/tests/appsec/iast/source/test_body.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import coverage, missing_feature, bug
+from utils import coverage, missing_feature, bug, features
from .._test_iast_fixtures import BaseSourceTest
+@features.iast_source_body
@coverage.basic
class TestRequestBody(BaseSourceTest):
"""Verify that request json body is tainted"""
diff --git a/tests/appsec/iast/source/test_cookie_name.py b/tests/appsec/iast/source/test_cookie_name.py
index 8087ff59ba7..023699bd912 100644
--- a/tests/appsec/iast/source/test_cookie_name.py
+++ b/tests/appsec/iast/source/test_cookie_name.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import coverage, bug, missing_feature
+from utils import coverage, bug, missing_feature, features
from .._test_iast_fixtures import BaseSourceTest
@coverage.basic
+@features.iast_source_cookie_name
class TestCookieName(BaseSourceTest):
"""Verify that request cookies are tainted"""
diff --git a/tests/appsec/iast/source/test_cookie_value.py b/tests/appsec/iast/source/test_cookie_value.py
index f79ca36d08c..f741bd7a0d6 100644
--- a/tests/appsec/iast/source/test_cookie_value.py
+++ b/tests/appsec/iast/source/test_cookie_value.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, bug, missing_feature
+from utils import context, coverage, bug, missing_feature, features
from .._test_iast_fixtures import BaseSourceTest
@coverage.basic
+@features.iast_source_cookie_value
class TestCookieValue(BaseSourceTest):
"""Verify that request cookies are tainted"""
diff --git a/tests/appsec/iast/source/test_header_name.py b/tests/appsec/iast/source/test_header_name.py
index 30e3334a521..8392e5a0105 100644
--- a/tests/appsec/iast/source/test_header_name.py
+++ b/tests/appsec/iast/source/test_header_name.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, bug
+from utils import context, coverage, bug, features
from .._test_iast_fixtures import BaseSourceTest
@coverage.basic
+@features.iast_source_header_name
class TestHeaderName(BaseSourceTest):
"""Verify that request headers name are tainted"""
diff --git a/tests/appsec/iast/source/test_header_value.py b/tests/appsec/iast/source/test_header_value.py
index 6b0d231cc02..88831cae736 100644
--- a/tests/appsec/iast/source/test_header_value.py
+++ b/tests/appsec/iast/source/test_header_value.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, bug, missing_feature
+from utils import context, coverage, bug, missing_feature, features
from .._test_iast_fixtures import BaseSourceTest
@coverage.basic
+@features.iast_source_header_value
class TestHeaderValue(BaseSourceTest):
"""Verify that request headers are tainted"""
diff --git a/tests/appsec/iast/source/test_parameter_name.py b/tests/appsec/iast/source/test_parameter_name.py
index 344330a9280..c4a5114347c 100644
--- a/tests/appsec/iast/source/test_parameter_name.py
+++ b/tests/appsec/iast/source/test_parameter_name.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import coverage, missing_feature, bug
+from utils import coverage, missing_feature, bug, features
from .._test_iast_fixtures import BaseSourceTest
+@features.iast_source_request_parameter_name
@coverage.basic
class TestParameterName(BaseSourceTest):
"""Verify that request parameters are tainted"""
diff --git a/tests/appsec/iast/source/test_parameter_value.py b/tests/appsec/iast/source/test_parameter_value.py
index 371aecf8390..819075766f4 100644
--- a/tests/appsec/iast/source/test_parameter_value.py
+++ b/tests/appsec/iast/source/test_parameter_value.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, coverage, missing_feature, bug
+from utils import context, coverage, missing_feature, bug, features
from .._test_iast_fixtures import BaseSourceTest
@coverage.basic
+@features.iast_source_request_parameter_value
class TestParameterValue(BaseSourceTest):
"""Verify that request parameters are tainted"""
diff --git a/tests/appsec/test_alpha.py b/tests/appsec/test_alpha.py
index 89e0e7c963f..610721ef4b5 100644
--- a/tests/appsec/test_alpha.py
+++ b/tests/appsec/test_alpha.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, weblog, interfaces, missing_feature, bug, coverage
+from utils import context, weblog, interfaces, missing_feature, bug, coverage, features
@missing_feature(context.library == "ruby" and context.libddwaf_version is None)
@coverage.basic
+@features.threats_alpha_preview
class Test_Basic:
""" Detect attacks on raw URI and headers with default rules """
diff --git a/tests/appsec/test_automated_login_events.py b/tests/appsec/test_automated_login_events.py
index 3a49e09dac9..29aa1232fdc 100644
--- a/tests/appsec/test_automated_login_events.py
+++ b/tests/appsec/test_automated_login_events.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2022 Datadog, Inc.
-from utils import weblog, interfaces, context, missing_feature, scenarios, coverage, rfc, bug
+from utils import weblog, interfaces, context, missing_feature, scenarios, coverage, rfc, bug, features
@rfc("https://docs.google.com/document/d/1-trUpphvyZY7k5ldjhW-MgqWl0xOm7AMEQDJEAZ63_Q/edit#heading=h.8d3o7vtyu1y1")
@coverage.good
+@features.user_monitoring
class Test_Login_Events:
"Test login success/failure use cases"
# User entries in the internal DB:
diff --git a/tests/appsec/test_conf.py b/tests/appsec/test_conf.py
index 8c94fab838a..e823c0aadf3 100644
--- a/tests/appsec/test_conf.py
+++ b/tests/appsec/test_conf.py
@@ -2,18 +2,21 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import weblog, context, coverage, interfaces, missing_feature, irrelevant, rfc, scenarios
+from utils import weblog, context, coverage, interfaces, missing_feature, irrelevant, rfc, scenarios, features
from utils.tools import nested_lookup
from tests.constants import PYTHON_RELEASE_GA_1_1
from .waf.utils import rules
@coverage.not_testable
+@features.appsec_onboarding
+@features.threats_configuration
class Test_OneVariableInstallation:
"""Installation with 1 env variable"""
@coverage.basic
+@features.threats_configuration
class Test_StaticRuleSet:
"""Appsec loads rules from a static rules file"""
@@ -28,6 +31,7 @@ def test_basic_hardcoded_ruleset(self):
@coverage.basic
+@features.threats_configuration
class Test_RuleSet_1_2_4:
""" AppSec uses rule set 1.2.4 or higher """
@@ -36,6 +40,7 @@ def test_main(self):
@coverage.basic
+@features.threats_configuration
class Test_RuleSet_1_2_5:
""" AppSec uses rule set 1.2.5 or higher """
@@ -44,6 +49,7 @@ def test_main(self):
@coverage.good
+@features.threats_configuration
class Test_RuleSet_1_3_1:
""" AppSec uses rule set 1.3.1 or higher """
@@ -70,6 +76,7 @@ def test_nosqli_keys_with_brackets(self):
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2355333252/Environment+Variables")
@coverage.basic
+@features.threats_configuration
class Test_ConfigurationVariables:
""" Configuration environment variables """
diff --git a/tests/appsec/test_docs.py b/tests/appsec/test_docs.py
index 7d42f4186e7..a481d378e92 100644
--- a/tests/appsec/test_docs.py
+++ b/tests/appsec/test_docs.py
@@ -2,7 +2,7 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import coverage
+from utils import coverage, features
@coverage.not_testable
@@ -11,6 +11,7 @@ class Test_InstallationInstructions:
@coverage.not_testable
+@features.procedure_to_debug_install
class Test_InstallationDebugProcedure:
"""Procedure to debug install"""
diff --git a/tests/appsec/test_event_tracking.py b/tests/appsec/test_event_tracking.py
index b03a98bedea..49c9ea85c17 100644
--- a/tests/appsec/test_event_tracking.py
+++ b/tests/appsec/test_event_tracking.py
@@ -1,10 +1,11 @@
# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import weblog, coverage, interfaces
+from utils import weblog, coverage, interfaces, features
@coverage.basic
+@features.user_monitoring
class Test_UserLoginSuccessEvent:
"""Success test for User Login Event SDK for AppSec"""
@@ -39,6 +40,7 @@ def validate_user_login_success_tags(span):
@coverage.basic
+@features.user_monitoring
class Test_UserLoginFailureEvent:
"""Failure test for User Login Event SDK for AppSec"""
@@ -74,6 +76,7 @@ def validate_user_login_failure_tags(span):
@coverage.basic
+@features.custom_business_logic_events
class Test_CustomEvent:
"""Test for Custom Event SDK for AppSec"""
diff --git a/tests/appsec/test_identify.py b/tests/appsec/test_identify.py
index 13d4bb815bf..a6d9426cb92 100644
--- a/tests/appsec/test_identify.py
+++ b/tests/appsec/test_identify.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import weblog, coverage, interfaces
+from utils import weblog, coverage, interfaces, features
@coverage.basic
+@features.user_monitoring
class Test_Basic:
"""Basic tests for Identify SDK for AppSec"""
diff --git a/tests/appsec/test_reports.py b/tests/appsec/test_reports.py
index 1da4c9ff025..b7f74453dd0 100644
--- a/tests/appsec/test_reports.py
+++ b/tests/appsec/test_reports.py
@@ -5,11 +5,12 @@
import socket
-from utils import weblog, context, coverage, interfaces, bug, missing_feature, rfc
+from utils import weblog, context, coverage, interfaces, bug, missing_feature, rfc, features
@bug(context.library == "python@1.1.0", reason="a PR was not included in the release")
@coverage.basic
+@features.security_events_metadata
class Test_StatusCode:
"""Appsec reports good status code"""
@@ -44,6 +45,7 @@ def check_http_code(span, appsec_data):
@missing_feature(
True, reason="Bug on system test: with the runner on the host, we do not have the real IP from weblog POV"
)
+@features.security_events_metadata
class Test_HttpClientIP:
"""AppSec reports good http client IP"""
@@ -77,6 +79,7 @@ def validator(span, appsec_data):
@bug(context.library == "python@1.1.0", reason="a PR was not included in the release")
@coverage.good
+@features.security_events_metadata
class Test_Info:
"""Environment (production, staging) from DD_ENV variable"""
@@ -109,6 +112,7 @@ def _check_service(span, appsec_data):
@missing_feature(context.library == "ruby" and context.libddwaf_version is None)
@bug(context.library == "python@1.1.0", reason="a PR was not included in the release")
@coverage.good
+@features.security_events_metadata
class Test_RequestHeaders:
"""Request Headers for IP resolution"""
@@ -145,6 +149,7 @@ def test_http_request_headers(self):
@coverage.basic
+@features.security_events_metadata
class Test_TagsFromRule:
"""Tags (Category & event type) from the rule"""
@@ -164,6 +169,7 @@ def test_basic(self):
@coverage.basic
+@features.security_events_metadata
class Test_ExtraTagsFromRule:
"""Extra tags may be added to the rule match since libddwaf 1.10.0"""
@@ -179,6 +185,7 @@ def test_basic(self):
@coverage.basic
+@features.security_events_metadata
class Test_AttackTimestamp:
"""Attack timestamp"""
diff --git a/tests/appsec/test_shell_execution.py b/tests/appsec/test_shell_execution.py
index 0fc7ce14088..51cbe8f8413 100644
--- a/tests/appsec/test_shell_execution.py
+++ b/tests/appsec/test_shell_execution.py
@@ -3,24 +3,13 @@
# Copyright 2021 Datadog, Inc.
import json
-import sys
-from utils import (
- bug,
- context,
- coverage,
- interfaces,
- irrelevant,
- missing_feature,
- rfc,
- scenarios,
- weblog,
- flaky,
-)
+from utils import coverage, interfaces, weblog, features
+@features.appsec_shell_execution_tracing
@coverage.basic
class Test_ShellExecution:
- """ Test shell execution tracing """
+ """Test shell execution tracing"""
def setup_track_cmd_exec(self):
self.r_cmd_exec = weblog.post(
diff --git a/tests/appsec/test_traces.py b/tests/appsec/test_traces.py
index 2cc2b5813be..019dba0af22 100644
--- a/tests/appsec/test_traces.py
+++ b/tests/appsec/test_traces.py
@@ -3,17 +3,7 @@
# Copyright 2021 Datadog, Inc.
from tests.constants import PYTHON_RELEASE_GA_1_1
-from utils import (
- weblog,
- bug,
- context,
- coverage,
- interfaces,
- irrelevant,
- rfc,
- missing_feature,
- scenarios,
-)
+from utils import weblog, bug, context, coverage, interfaces, irrelevant, rfc, missing_feature, scenarios, features
from utils.tools import nested_lookup
@@ -22,6 +12,7 @@
@bug(context.library == "python@1.1.0", reason="a PR was not included in the release")
@coverage.good
+@features.security_events_metadata
class Test_RetainTraces:
"""Retain trace (manual keep & appsec.event = true)"""
@@ -62,6 +53,7 @@ def validate_appsec_event_span_tags(span):
@coverage.good
+@features.security_events_metadata
class Test_AppSecEventSpanTags:
"""AppSec correctly fill span tags."""
@@ -153,6 +145,8 @@ def validator(span):
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2365948382/Sensitive+Data+Obfuscation")
@coverage.good
+@features.sensitive_data_obfuscation
+@features.security_events_metadata
class Test_AppSecObfuscator:
"""AppSec obfuscates sensitive data."""
@@ -314,6 +308,7 @@ def validate_appsec_span_tags(span, appsec_data): # pylint: disable=unused-argu
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2186870984/HTTP+header+collection")
@coverage.good
+@features.security_events_metadata
class Test_CollectRespondHeaders:
"""AppSec should collect some headers for http.response and store them in span tags."""
@@ -334,5 +329,6 @@ def validate_response_headers(span):
@coverage.not_implemented
+@features.security_events_metadata
class Test_DistributedTraceInfo:
"""Distributed traces info (Services, URL, trace id)"""
diff --git a/tests/appsec/waf/test_addresses.py b/tests/appsec/waf/test_addresses.py
index 9cb5cd719e3..7f346ac15bd 100644
--- a/tests/appsec/waf/test_addresses.py
+++ b/tests/appsec/waf/test_addresses.py
@@ -1,20 +1,11 @@
# Unless explicitly stated otherwise all files in this repository are licensed under the the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import (
- weblog,
- bug,
- context,
- coverage,
- interfaces,
- irrelevant,
- missing_feature,
- rfc,
- scenarios,
-)
+from utils import weblog, bug, context, coverage, interfaces, irrelevant, missing_feature, rfc, scenarios, features
@coverage.basic
+@features.http_threats_management
class Test_UrlQueryKey:
"""Appsec supports keys on server.request.query"""
@@ -28,6 +19,7 @@ def test_query_key(self):
@coverage.good
+@features.http_threats_management
class Test_UrlQuery:
"""Appsec supports values on server.request.query"""
@@ -59,6 +51,7 @@ def test_query_with_strict_regex(self):
@coverage.basic
+@features.http_threats_management
class Test_UrlRaw:
"""Appsec supports server.request.uri.raw"""
@@ -71,6 +64,7 @@ def test_path(self):
@coverage.good
+@features.http_threats_management
class Test_Headers:
"""Appsec supports server.request.headers.no_cookies"""
@@ -139,6 +133,7 @@ def test_specific_wrong_key(self):
@coverage.good
+@features.http_threats_management
class Test_Cookies:
"""Appsec supports server.request.cookies"""
@@ -237,6 +232,7 @@ def test_cookies_with_special_chars2_custom_rules(self):
@coverage.basic
+@features.http_threats_management
class Test_BodyRaw:
"""Appsec supports
"""
@@ -251,6 +247,7 @@ def test_raw_body(self):
@coverage.basic
@bug(context.library == "nodejs@2.8.0", reason="Capability to read body content is broken")
+@features.http_threats_management
class Test_BodyUrlEncoded:
"""Appsec supports """
@@ -278,6 +275,7 @@ def test_body_value(self):
@coverage.basic
@bug(context.library == "nodejs@2.8.0", reason="Capability to read body content is broken")
+@features.http_threats_management
class Test_BodyJson:
"""Appsec supports """
@@ -312,6 +310,7 @@ def test_json_array(self):
@bug(context.library == "nodejs@2.8.0", reason="Capability to read body content is broken")
+@features.http_threats_management
@coverage.basic
class Test_BodyXml:
"""Appsec supports """
@@ -345,16 +344,19 @@ def test_xml_content(self):
@coverage.not_implemented
+@features.http_threats_management
class Test_Method:
"""Appsec supports server.request.method"""
@coverage.not_implemented
+@features.http_threats_management
class Test_ClientIP:
"""Appsec supports server.request.client_ip"""
@coverage.good
+@features.http_threats_management
class Test_ResponseStatus:
"""Appsec supports values on server.response.status"""
@@ -372,6 +374,7 @@ def test_basic(self):
@coverage.basic
+@features.http_threats_management
class Test_PathParams:
"""Appsec supports values on server.request.path_params"""
@@ -386,6 +389,8 @@ def test_security_scanner(self):
@coverage.basic
+@features.http_threats_management
+@features.grpc_threats_management
class Test_gRPC:
"""Appsec supports address grpc.server.request.message"""
@@ -404,15 +409,20 @@ def test_basic(self):
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2278064284/gRPC+Protocol+Support")
@coverage.not_implemented
+@features.http_threats_management
+@features.grpc_threats_management
class Test_FullGrpc:
"""Full gRPC support"""
@coverage.not_implemented
+@features.http_threats_management
+@features.graphql_threats_detection
class Test_GraphQL:
"""GraphQL support"""
@coverage.not_implemented
+@features.http_threats_management
class Test_Lambda:
"""Lambda support"""
diff --git a/tests/appsec/waf/test_miscs.py b/tests/appsec/waf/test_miscs.py
index 8310dc507d0..68ef4193b18 100644
--- a/tests/appsec/waf/test_miscs.py
+++ b/tests/appsec/waf/test_miscs.py
@@ -2,12 +2,13 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, weblog, interfaces, bug, coverage, missing_feature, scenarios
+from utils import context, weblog, interfaces, bug, coverage, missing_feature, scenarios, features
from .utils import rules
@bug(context.library == "python@1.1.0", reason="a PR was not included in the release")
@coverage.basic
+@features.http_threats_management
class Test_404:
"""Appsec WAF misc tests"""
@@ -42,6 +43,7 @@ def test_multiple_hightlight(self):
@coverage.good
+@features.http_threats_management
class Test_MultipleAttacks:
"""If several attacks are sent threw one requests, all of them are reported"""
@@ -86,6 +88,7 @@ def test_main(self):
@coverage.basic
+@features.threats_configuration
class Test_NoWafTimeout:
"""With an high value of DD_APPSEC_WAF_TIMEOUT, there is no WAF timeout"""
diff --git a/tests/appsec/waf/test_reports.py b/tests/appsec/waf/test_reports.py
index 94e413f78d4..e24e1a5bc88 100644
--- a/tests/appsec/waf/test_reports.py
+++ b/tests/appsec/waf/test_reports.py
@@ -4,10 +4,11 @@
import re
import json
-from utils import weblog, context, interfaces, irrelevant, coverage, scenarios
+from utils import weblog, context, interfaces, irrelevant, coverage, scenarios, features
@coverage.good
+@features.support_in_app_waf_metrics_report
class Test_Monitoring:
"""Support In-App WAF monitoring tags and metrics"""
diff --git a/tests/test_identify.py b/tests/test_identify.py
index 87b03f65b6c..f480e18e731 100644
--- a/tests/test_identify.py
+++ b/tests/test_identify.py
@@ -2,7 +2,7 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import weblog, bug, context, coverage, interfaces, rfc
+from utils import weblog, bug, context, coverage, interfaces, rfc, features
def assertTagInSpanMeta(span, tag, expected):
@@ -61,6 +61,7 @@ def test_identify_tags_with_attack(self):
@rfc("https://docs.google.com/document/d/1T3qAE5nol18psOaHESQ3r-WRiZWss9nyGmroShug8ao/edit#heading=h.3wmduzc8mwe1")
@coverage.basic
+@features.propagation_of_user_id_rfc
class Test_Propagate_Legacy:
"""Propagation tests for Identify SDK"""
@@ -85,6 +86,7 @@ def test_identify_tags_incoming(self):
@rfc("https://docs.google.com/document/d/1T3qAE5nol18psOaHESQ3r-WRiZWss9nyGmroShug8ao/edit#heading=h.3wmduzc8mwe1")
@coverage.basic
+@features.propagation_of_user_id_rfc
class Test_Propagate:
"""Propagation tests for Identify SDK"""
diff --git a/tests/test_library_conf.py b/tests/test_library_conf.py
index e8eb2858fb7..cf29812feeb 100644
--- a/tests/test_library_conf.py
+++ b/tests/test_library_conf.py
@@ -2,11 +2,12 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import coverage, weblog, interfaces, scenarios
+from utils import coverage, weblog, interfaces, scenarios, features
# basic / legacy tests, just tests user-agent can be received as a tag
@coverage.basic
+@features.security_events_metadata
class Test_HeaderTags:
"""DD_TRACE_HEADER_TAGS env var support"""
diff --git a/tests/test_miscs.py b/tests/test_miscs.py
index 6247fef545d..cbcd04d4c35 100644
--- a/tests/test_miscs.py
+++ b/tests/test_miscs.py
@@ -2,9 +2,10 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2022 Datadog, Inc.
-from utils import weblog, interfaces
+from utils import weblog, interfaces, features
+@features.unix_domain_sockets_support_for_traces
class Test_Basic:
""" Make sure the spans endpoint is successful """
diff --git a/tests/test_semantic_conventions.py b/tests/test_semantic_conventions.py
index b1cac8406d5..a3abaf93305 100644
--- a/tests/test_semantic_conventions.py
+++ b/tests/test_semantic_conventions.py
@@ -5,7 +5,7 @@
import re
from urllib.parse import urlparse
-from utils import context, interfaces, bug, missing_feature
+from utils import context, interfaces, bug, missing_feature, features
RUNTIME_LANGUAGE_MAP = {
"nodejs": "javascript",
@@ -129,6 +129,8 @@ def get_component_name(weblog_variant, language, span_name):
return expected_component
+@features.runtime_id_in_span_metadata_for_service_entry_spans
+@features.unix_domain_sockets_support_for_traces
class Test_Meta:
"""meta object in spans respect all conventions"""
@@ -296,6 +298,7 @@ def validator(span):
assert len(list(interfaces.library.get_root_spans())) != 0, "Did not recieve any root spans to validate."
+@features.add_metadata_globally_to_all_spans_dd_tags
class Test_MetaDatadogTags:
"""Spans carry meta tags that were set in DD_TAGS tracer environment"""
diff --git a/tests/test_smoke.py b/tests/test_smoke.py
index ee0cf2e4279..d1fe0739d94 100644
--- a/tests/test_smoke.py
+++ b/tests/test_smoke.py
@@ -2,9 +2,10 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.
-from utils import context, weblog, interfaces
+from utils import context, weblog, interfaces, features
+@features.unix_domain_sockets_support_for_traces
class Test_Backend:
"""Misc test around agent/backend communication"""
@@ -13,6 +14,7 @@ def test_good_backend(self):
interfaces.agent.assert_use_domain(context.dd_site)
+@features.unix_domain_sockets_support_for_traces
class Test_Library:
"""Misc test around library/agent communication"""
diff --git a/tests/test_standard_tags.py b/tests/test_standard_tags.py
index ef9becaceb7..2bbddb437dc 100644
--- a/tests/test_standard_tags.py
+++ b/tests/test_standard_tags.py
@@ -2,10 +2,11 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2022 Datadog, Inc.
-from utils import bug, context, coverage, interfaces, irrelevant, missing_feature, rfc, weblog
+from utils import bug, context, coverage, interfaces, irrelevant, missing_feature, rfc, weblog, features
@coverage.good
+@features.security_events_metadata
class Test_StandardTagsMethod:
"""Tests to verify that libraries annotate spans with correct http.method tags"""
@@ -32,6 +33,7 @@ def test_method_trace(self):
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2490990623/QueryString+-+Sensitive+Data+Obfuscation")
@coverage.basic
+@features.security_events_metadata
class Test_StandardTagsUrl:
"""Tests to verify that libraries annotate spans with correct http.url tags"""
@@ -160,6 +162,7 @@ def test_multiple_matching_substring(self):
@coverage.basic
+@features.security_events_metadata
class Test_StandardTagsUserAgent:
"""Tests to verify that libraries annotate spans with correct http.useragent tags"""
@@ -173,6 +176,7 @@ def test_useragent(self):
@coverage.good
+@features.security_events_metadata
class Test_StandardTagsStatusCode:
"""Tests to verify that libraries annotate spans with correct http.status_code tags"""
@@ -186,6 +190,7 @@ def test_status_code(self):
@coverage.basic
+@features.security_events_metadata
class Test_StandardTagsRoute:
"""Tests to verify that libraries annotate spans with correct http.route tags"""
@@ -217,6 +222,7 @@ def test_route(self):
@rfc("https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2118779066/Client+IP+addresses+resolution")
@coverage.basic
+@features.security_events_metadata
class Test_StandardTagsClientIp:
"""Tests to verify that libraries annotate spans with correct http.client_ip tags"""
diff --git a/utils/_features.py b/utils/_features.py
index fb76803a77b..34914e45b0f 100644
--- a/utils/_features.py
+++ b/utils/_features.py
@@ -1,168 +1,1300 @@
+# pylint: disable=too-many-lines
+
import pytest
-import requests
-def _feature(feature_id: int):
- def decorate(test_object):
- pytest.mark.features(feature_id=feature_id)(test_object)
+class features:
+ """
+ Data source is https://dd-feature-parity.azurewebsites.net/Import/Features
+
+ run this command to get new features:
+
+ ```
+ PYTHONPATH=. python utils/scripts/update_features.py
+ ```
+ """
+
+ @staticmethod
+ def add_metadata_globally_to_all_spans_dd_tags(test_object):
+ """
+ Add Metadata globally to all spans (DD_TAGS)
+
+ https://feature-parity.us1.prod.dog/#/?feature=1
+ """
+ pytest.mark.features(feature_id=1)(test_object)
return test_object
- return staticmethod(decorate)
+ @staticmethod
+ def change_agent_hostname_dd_agent_host(test_object):
+ """
+ Change Agent hostname (DD_AGENT_HOST)
+ https://feature-parity.us1.prod.dog/#/?feature=2
+ """
+ pytest.mark.features(feature_id=2)(test_object)
+ return test_object
-class features:
- """https://dd-feature-parity.azurewebsites.net/Import/Features"""
-
- add_metadata_globally_to_all_spans_dd_tags = _feature(1)
- change_agent_hostname_dd_agent_host = _feature(2)
- add_metadata_to_spans_via_tags_dd_trace_analytics_enabled = _feature(3)
- trace_search_automatic_config = _feature(4)
- manual_trace_id_injection_into_logs = _feature(5)
- unix_domain_sockets_support_for_traces = _feature(6)
- unix_domain_sockets_automatic_detection = _feature(7)
- twl_customer_controls_ingestion_dd_trace_sampling_rules = _feature(8)
- synthetic_apm_http_header_span_tag_x_datadog_origin = _feature(9)
- log_tracer_status_at_startup = _feature(10)
- fargate_14_tagging_support = _feature(11)
- container_tagging = _feature(12)
- b3_headers_injection_and_extraction = _feature(13)
- unix_domain_sockets_support_for_metrics = _feature(14)
- support_ddmeasured = _feature(15)
- dd_service_mapping = _feature(16)
- datadog_managed_dogstatsd_client = _feature(17)
- http_headers_as_tags_dd_trace_header_tags = _feature(18)
- dd_profiling_enabled = _feature(19)
- dogstatsd_unified_service_tagging = _feature(20)
- trace_log_exporting_for_aws_lambda = _feature(21)
- runtime_id_in_span_metadata_for_service_entry_spans = _feature(22)
- partial_flush = _feature(23)
- partial_flush_on_by_default = _feature(24)
- automatic_trace_id_injection_into_logs = _feature(25)
- mapping_http_status_codes_to_errors = _feature(26)
- log_pipelines_updated_for_log_injection = _feature(27)
- inject_service_env_version_into_logs = _feature(28)
- top_level_detection_in_tracer = _feature(29)
- use_sampling_priorities_2_1_in_rules_based_sampler = _feature(30)
- trace_annotation = _feature(31)
- runtime_metrics = _feature(32)
- logs_throttling = _feature(33)
- post_processing_traces = _feature(34)
- span_baggage_item = _feature(35)
- tracer_health_metrics = _feature(36)
- kafka_tracing = _feature(37)
- numeric_tags_for_trace_search_analytics_step_1 = _feature(38)
- grpc_integration_tags = _feature(39)
- dd_trace_config_file = _feature(40)
- dd_trace_methods = _feature(41)
- dd_tags_space_separated_tags = _feature(42)
- report_tracer_drop_rate_ddtracer_kr = _feature(43)
- obfuscation_of_pii_from_web_span_resource_names = _feature(44)
- windows_named_pipe_support_for_traces = _feature(45)
- setting_to_rename_service_by_tag_split_by_tag = _feature(46)
- collect_application_version_information = _feature(47)
- ensure_that_sampling_is_consistent_across_languages = _feature(48)
- user_troubleshooting_tool = _feature(49)
- option_to_remap_apm_error_response_severity_eg_404_to_error = _feature(50)
- obfuscation_of_httpurl_span_tag = _feature(51)
- dd_trace_report_hostname = _feature(52)
- windows_named_pipe_support_for_metrics = _feature(53)
- ensure_consistent_http_client_integration_tags = _feature(54)
- aws_sdk_integration_tags = _feature(55)
- dont_set_username_tag_because_its_pii = _feature(56)
- trace_client_app_tagging = _feature(57)
- client_split_by_domain_service_host = _feature(58)
- horizontal_propagation_of_x_datadog_tags_between_services = _feature(59)
- vertical_propagation_of_x_datadog_tags_onto_each_chunk_root_span = _feature(60)
- creation_and_propagation_of_ddpdm = _feature(61)
- client_side_stats_supported = _feature(62)
- client_side_stats_on_by_default = _feature(63)
- instrumentation_telemetry_enabled_by_default = _feature(64)
- dd_instrumentation_telemetry_enabled_supported = _feature(65)
- app_environment_collected = _feature(66)
- dependencies_collected = _feature(67)
- integrations_enabled_collected = _feature(68)
- tracer_configurations_collected = _feature(69)
- heart_beat_collected = _feature(70)
- app_close_collected = _feature(71)
- logs_collected = _feature(72)
- metrics_collected = _feature(73)
- api_v2_implemented = _feature(74)
- app_client_configuration_change_event = _feature(75)
- app_product_change_event = _feature(76)
- app_extended_heartbeat_event = _feature(77)
- message_batch = _feature(78)
- app_started_changes = _feature(79)
- dd_telemetry_dependency_collection_enabled_supported = _feature(80)
- additional_http_headers_supported = _feature(81)
- remote_config_object_supported = _feature(82)
- w3c_headers_injection_and_extraction = _feature(83)
- otel_api = _feature(84)
- trace_id_generation_propagation_128_bit = _feature(85)
- span_events = _feature(86)
- span_links = _feature(87)
- client_ip_adress_collection_dd_trace_client_ip_enabled = _feature(88)
- host_auto_instrumentation = _feature(89)
- container_auto_instrumentation = _feature(90)
- collect_http_post_data_and_headers = _feature(94)
- weak_hash_vulnerability_detection = _feature(96)
- db_integrations = _feature(98)
- http_threats_management = _feature(99)
- weak_cipher_detection = _feature(100)
- threats_alpha_preview = _feature(110)
- procedure_to_debug_install = _feature(113)
- security_events_metadata = _feature(124)
- rate_limiter = _feature(134)
- support_in_app_waf_metrics_report = _feature(140)
- user_monitoring = _feature(141)
- serialize_waf_rules_without_limiting_their_sizes = _feature(142)
- threats_configuration = _feature(143)
- sensitive_data_obfuscation = _feature(144)
- propagation_of_user_id_rfc = _feature(146)
- onboarding = _feature(154)
- deactivate_rules_using_rc = _feature(157)
- shell_execution_tracing = _feature(158)
- appsec_userid_blocking = _feature(160)
- custom_business_logic_events = _feature(161)
- graphql_threats_detection = _feature(162)
- iast_sink_sql_injection = _feature(165)
- iast_sink_command_injection = _feature(166)
- iast_sink_path_traversal = _feature(167)
- iast_sink_ldap_injection = _feature(168)
- iast_source_request_parameter_value = _feature(169)
- iast_source_request_parameter_name = _feature(170)
- iast_source_header_value = _feature(171)
- iast_source_header_name = _feature(172)
- iast_source_cookie_value = _feature(173)
- iast_source_cookie_name = _feature(174)
- iast_source_body = _feature(175)
- grpc_threats_management = _feature(176)
- telemetry = _feature(178)
- kafkaspan_creationcontext_propagation_with_dd_trace_py = _feature(192)
-
-
-def _main():
- """Display missing features"""
-
- existing_features = set()
- for attr in dir(features):
- if attr.startswith("__"):
- continue
-
- decorator = getattr(features, attr)
-
- def obj():
- pass
-
- obj = decorator(obj)
-
- existing_features.add(obj.pytestmark[0].kwargs["feature_id"])
-
- data = requests.get("https://dd-feature-parity.azurewebsites.net/Import/Features", timeout=10).json()
- for feature in data:
- feature_id = feature["id"]
- if feature_id not in existing_features:
- print(f" {feature['codeSafeName'].lower()} = _feature({feature_id})")
-
-
-if __name__ == "__main__":
- _main()
+ @staticmethod
+ def add_metadata_to_spans_via_tags_dd_trace_analytics_enabled(test_object):
+ """
+ Add metadata to spans via tags (DD_TRACE_ANALYTICS_ENABLED)
+
+ https://feature-parity.us1.prod.dog/#/?feature=3
+ """
+ pytest.mark.features(feature_id=3)(test_object)
+ return test_object
+
+ @staticmethod
+ def trace_search_automatic_config(test_object):
+ """
+ Trace Search - automatic config
+
+ https://feature-parity.us1.prod.dog/#/?feature=4
+ """
+ pytest.mark.features(feature_id=4)(test_object)
+ return test_object
+
+ @staticmethod
+ def manual_trace_id_injection_into_logs(test_object):
+ """
+ Manual Trace-ID injection into Logs
+
+ https://feature-parity.us1.prod.dog/#/?feature=5
+ """
+ pytest.mark.features(feature_id=5)(test_object)
+ return test_object
+
+ @staticmethod
+ def unix_domain_sockets_support_for_traces(test_object):
+ """
+ Unix Domain Sockets support for traces
+
+ https://feature-parity.us1.prod.dog/#/?feature=6
+ """
+
+ from utils._context.core import context
+
+ if "uds" in context.weblog_variant:
+ pytest.mark.features(feature_id=6)(test_object)
+
+ return test_object
+
+ @staticmethod
+ def unix_domain_sockets_automatic_detection(test_object):
+ """
+ Unix Domain Sockets automatic detection
+
+ https://feature-parity.us1.prod.dog/#/?feature=7
+ """
+ pytest.mark.features(feature_id=7)(test_object)
+ return test_object
+
+ @staticmethod
+ def twl_customer_controls_ingestion_dd_trace_sampling_rules(test_object):
+ """
+ TwL - Customer Controls Ingestion (DD_TRACE_SAMPLING RULES)
+
+ https://feature-parity.us1.prod.dog/#/?feature=8
+ """
+ pytest.mark.features(feature_id=8)(test_object)
+ return test_object
+
+ @staticmethod
+ def synthetic_apm_http_header_span_tag_x_datadog_origin(test_object):
+ """
+ Synthetic APM (http header ▶ span tag) (x-datadog-origin))
+
+ https://feature-parity.us1.prod.dog/#/?feature=9
+ """
+ pytest.mark.features(feature_id=9)(test_object)
+ return test_object
+
+ @staticmethod
+ def log_tracer_status_at_startup(test_object):
+ """
+ Log Tracer status at startup
+
+ https://feature-parity.us1.prod.dog/#/?feature=10
+ """
+ pytest.mark.features(feature_id=10)(test_object)
+ return test_object
+
+ @staticmethod
+ def fargate_14_tagging_support(test_object):
+ """
+ Fargate 1.4 Tagging Support
+
+ https://feature-parity.us1.prod.dog/#/?feature=11
+ """
+ pytest.mark.features(feature_id=11)(test_object)
+ return test_object
+
+ @staticmethod
+ def container_tagging(test_object):
+ """
+ Container tagging
+
+ https://feature-parity.us1.prod.dog/#/?feature=12
+ """
+ pytest.mark.features(feature_id=12)(test_object)
+ return test_object
+
+ @staticmethod
+ def b3_headers_injection_and_extraction(test_object):
+ """
+ B3 headers injection and extraction
+
+ https://feature-parity.us1.prod.dog/#/?feature=13
+ """
+ pytest.mark.features(feature_id=13)(test_object)
+ return test_object
+
+ @staticmethod
+ def unix_domain_sockets_support_for_metrics(test_object):
+ """
+ Unix Domain Sockets support for metrics
+
+ https://feature-parity.us1.prod.dog/#/?feature=14
+ """
+ pytest.mark.features(feature_id=14)(test_object)
+ return test_object
+
+ @staticmethod
+ def support_ddmeasured(test_object):
+ """
+ Support _dd.measured
+
+ https://feature-parity.us1.prod.dog/#/?feature=15
+ """
+ pytest.mark.features(feature_id=15)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_service_mapping(test_object):
+ """
+ DD_SERVICE_MAPPING
+
+ https://feature-parity.us1.prod.dog/#/?feature=16
+ """
+ pytest.mark.features(feature_id=16)(test_object)
+ return test_object
+
+ @staticmethod
+ def datadog_managed_dogstatsd_client(test_object):
+ """
+ Datadog managed Dogstatsd client
+
+ https://feature-parity.us1.prod.dog/#/?feature=17
+ """
+ pytest.mark.features(feature_id=17)(test_object)
+ return test_object
+
+ @staticmethod
+ def http_headers_as_tags_dd_trace_header_tags(test_object):
+ """
+ HTTP Headers as Tags (DD_TRACE_HEADER_TAGS)
+
+ https://feature-parity.us1.prod.dog/#/?feature=18
+ """
+ pytest.mark.features(feature_id=18)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_profiling_enabled(test_object):
+ """
+ DD_PROFILING_ENABLED
+
+ https://feature-parity.us1.prod.dog/#/?feature=19
+ """
+ pytest.mark.features(feature_id=19)(test_object)
+ return test_object
+
+ @staticmethod
+ def dogstatsd_unified_service_tagging(test_object):
+ """
+ Dogstatsd unified service tagging
+
+ https://feature-parity.us1.prod.dog/#/?feature=20
+ """
+ pytest.mark.features(feature_id=20)(test_object)
+ return test_object
+
+ @staticmethod
+ def trace_log_exporting_for_aws_lambda(test_object):
+ """
+ Trace Log Exporting for AWS Lambda
+
+ https://feature-parity.us1.prod.dog/#/?feature=21
+ """
+ pytest.mark.features(feature_id=21)(test_object)
+ return test_object
+
+ @staticmethod
+ def runtime_id_in_span_metadata_for_service_entry_spans(test_object):
+ """
+ Runtime-id in span metadata for service entry spans
+
+ https://feature-parity.us1.prod.dog/#/?feature=22
+ """
+ pytest.mark.features(feature_id=22)(test_object)
+ return test_object
+
+ @staticmethod
+ def partial_flush(test_object):
+ """
+ Partial flush
+
+ https://feature-parity.us1.prod.dog/#/?feature=23
+ """
+ pytest.mark.features(feature_id=23)(test_object)
+ return test_object
+
+ @staticmethod
+ def partial_flush_on_by_default(test_object):
+ """
+ Partial flush on by default
+
+ https://feature-parity.us1.prod.dog/#/?feature=24
+ """
+ pytest.mark.features(feature_id=24)(test_object)
+ return test_object
+
+ @staticmethod
+ def automatic_trace_id_injection_into_logs(test_object):
+ """
+ Automatic Trace-id injection into Logs
+
+ https://feature-parity.us1.prod.dog/#/?feature=25
+ """
+ pytest.mark.features(feature_id=25)(test_object)
+ return test_object
+
+ @staticmethod
+ def mapping_http_status_codes_to_errors(test_object):
+ """
+ Mapping HTTP status codes to errors
+
+ https://feature-parity.us1.prod.dog/#/?feature=26
+ """
+ pytest.mark.features(feature_id=26)(test_object)
+ return test_object
+
+ @staticmethod
+ def log_pipelines_updated_for_log_injection(test_object):
+ """
+ Log Pipelines updated for log injection
+
+ https://feature-parity.us1.prod.dog/#/?feature=27
+ """
+ pytest.mark.features(feature_id=27)(test_object)
+ return test_object
+
+ @staticmethod
+ def inject_service_env_version_into_logs(test_object):
+ """
+ Inject service, env, version into logs
+
+ https://feature-parity.us1.prod.dog/#/?feature=28
+ """
+ pytest.mark.features(feature_id=28)(test_object)
+ return test_object
+
+ @staticmethod
+ def top_level_detection_in_tracer(test_object):
+ """
+ Top-level detection in tracer
+
+ https://feature-parity.us1.prod.dog/#/?feature=29
+ """
+ pytest.mark.features(feature_id=29)(test_object)
+ return test_object
+
+ @staticmethod
+ def use_sampling_priorities_2_1_in_rules_based_sampler(test_object):
+ """
+ Use sampling priorities +2/-1 in rules-based sampler
+
+ https://feature-parity.us1.prod.dog/#/?feature=30
+ """
+ pytest.mark.features(feature_id=30)(test_object)
+ return test_object
+
+ @staticmethod
+ def trace_annotation(test_object):
+ """
+ Trace Annotation
+
+ https://feature-parity.us1.prod.dog/#/?feature=31
+ """
+ pytest.mark.features(feature_id=31)(test_object)
+ return test_object
+
+ @staticmethod
+ def runtime_metrics(test_object):
+ """
+ Runtime metrics
+
+ https://feature-parity.us1.prod.dog/#/?feature=32
+ """
+ pytest.mark.features(feature_id=32)(test_object)
+ return test_object
+
+ @staticmethod
+ def logs_throttling(test_object):
+ """
+ Logs Throttling
+
+ https://feature-parity.us1.prod.dog/#/?feature=33
+ """
+ pytest.mark.features(feature_id=33)(test_object)
+ return test_object
+
+ @staticmethod
+ def post_processing_traces(test_object):
+ """
+ Post-Processing Traces
+
+ https://feature-parity.us1.prod.dog/#/?feature=34
+ """
+ pytest.mark.features(feature_id=34)(test_object)
+ return test_object
+
+ @staticmethod
+ def span_baggage_item(test_object):
+ """
+ Span Baggage item
+
+ https://feature-parity.us1.prod.dog/#/?feature=35
+ """
+ pytest.mark.features(feature_id=35)(test_object)
+ return test_object
+
+ @staticmethod
+ def tracer_health_metrics(test_object):
+ """
+ Tracer Health Metrics
+
+ https://feature-parity.us1.prod.dog/#/?feature=36
+ """
+ pytest.mark.features(feature_id=36)(test_object)
+ return test_object
+
+ @staticmethod
+ def kafka_tracing(test_object):
+ """
+ Kafka Tracing
+
+ https://feature-parity.us1.prod.dog/#/?feature=37
+ """
+ pytest.mark.features(feature_id=37)(test_object)
+ return test_object
+
+ @staticmethod
+ def numeric_tags_for_trace_search_analytics_step_1(test_object):
+ """
+ Numeric tags for Trace Search/Analytics (step 1)
+
+ https://feature-parity.us1.prod.dog/#/?feature=38
+ """
+ pytest.mark.features(feature_id=38)(test_object)
+ return test_object
+
+ @staticmethod
+ def grpc_integration_tags(test_object):
+ """
+ gRPC integration tags
+
+ https://feature-parity.us1.prod.dog/#/?feature=39
+ """
+ pytest.mark.features(feature_id=39)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_trace_config_file(test_object):
+ """
+ DD_TRACE_CONFIG_FILE
+
+ https://feature-parity.us1.prod.dog/#/?feature=40
+ """
+ pytest.mark.features(feature_id=40)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_trace_methods(test_object):
+ """
+ DD_TRACE_METHODS
+
+ https://feature-parity.us1.prod.dog/#/?feature=41
+ """
+ pytest.mark.features(feature_id=41)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_tags_space_separated_tags(test_object):
+ """
+ DD_TAGS space-separated tags
+
+ https://feature-parity.us1.prod.dog/#/?feature=42
+ """
+ pytest.mark.features(feature_id=42)(test_object)
+ return test_object
+
+ @staticmethod
+ def report_tracer_drop_rate_ddtracer_kr(test_object):
+ """
+ Report tracer drop rate (_dd.tracer_kr)
+
+ https://feature-parity.us1.prod.dog/#/?feature=43
+ """
+ pytest.mark.features(feature_id=43)(test_object)
+ return test_object
+
+ @staticmethod
+ def obfuscation_of_pii_from_web_span_resource_names(test_object):
+ """
+ Obfuscation of PII from web span resource names
+
+ https://feature-parity.us1.prod.dog/#/?feature=44
+ """
+ pytest.mark.features(feature_id=44)(test_object)
+ return test_object
+
+ @staticmethod
+ def windows_named_pipe_support_for_traces(test_object):
+ """
+ Windows named pipe support for traces
+
+ https://feature-parity.us1.prod.dog/#/?feature=45
+ """
+ pytest.mark.features(feature_id=45)(test_object)
+ return test_object
+
+ @staticmethod
+ def setting_to_rename_service_by_tag_split_by_tag(test_object):
+ """
+ Setting to rename service by tag (split-by-tag)
+
+ https://feature-parity.us1.prod.dog/#/?feature=46
+ """
+ pytest.mark.features(feature_id=46)(test_object)
+ return test_object
+
+ @staticmethod
+ def collect_application_version_information(test_object):
+ """
+ Collect application version information
+
+ https://feature-parity.us1.prod.dog/#/?feature=47
+ """
+ pytest.mark.features(feature_id=47)(test_object)
+ return test_object
+
+ @staticmethod
+ def ensure_that_sampling_is_consistent_across_languages(test_object):
+ """
+ Ensure that sampling is consistent across languages
+
+ https://feature-parity.us1.prod.dog/#/?feature=48
+ """
+ pytest.mark.features(feature_id=48)(test_object)
+ return test_object
+
+ @staticmethod
+ def user_troubleshooting_tool(test_object):
+ """
+ User Troubleshooting Tool
+
+ https://feature-parity.us1.prod.dog/#/?feature=49
+ """
+ pytest.mark.features(feature_id=49)(test_object)
+ return test_object
+
+ @staticmethod
+ def option_to_remap_apm_error_response_severity_eg_404_to_error(test_object):
+ """
+ Option to remap APM error response severity (e.g. 404 to error)
+
+ https://feature-parity.us1.prod.dog/#/?feature=50
+ """
+ pytest.mark.features(feature_id=50)(test_object)
+ return test_object
+
+ @staticmethod
+ def obfuscation_of_httpurl_span_tag(test_object):
+ """
+ Obfuscation of http.url span tag
+
+ https://feature-parity.us1.prod.dog/#/?feature=51
+ """
+ pytest.mark.features(feature_id=51)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_trace_report_hostname(test_object):
+ """
+ DD_TRACE_REPORT_HOSTNAME
+
+ https://feature-parity.us1.prod.dog/#/?feature=52
+ """
+ pytest.mark.features(feature_id=52)(test_object)
+ return test_object
+
+ @staticmethod
+ def windows_named_pipe_support_for_metrics(test_object):
+ """
+ Windows named pipe support for metrics
+
+ https://feature-parity.us1.prod.dog/#/?feature=53
+ """
+ pytest.mark.features(feature_id=53)(test_object)
+ return test_object
+
+ @staticmethod
+ def ensure_consistent_http_client_integration_tags(test_object):
+ """
+ Ensure consistent HTTP client integration tags
+
+ https://feature-parity.us1.prod.dog/#/?feature=54
+ """
+ pytest.mark.features(feature_id=54)(test_object)
+ return test_object
+
+ @staticmethod
+ def aws_sdk_integration_tags(test_object):
+ """
+ AWS SDK Integration Tags
+
+ https://feature-parity.us1.prod.dog/#/?feature=55
+ """
+ pytest.mark.features(feature_id=55)(test_object)
+ return test_object
+
+ @staticmethod
+ def dont_set_username_tag_because_its_pii(test_object):
+ """
+ Don't set username tag because it's PII
+
+ https://feature-parity.us1.prod.dog/#/?feature=56
+ """
+ pytest.mark.features(feature_id=56)(test_object)
+ return test_object
+
+ @staticmethod
+ def trace_client_app_tagging(test_object):
+ """
+ Trace Client App Tagging
+
+ https://feature-parity.us1.prod.dog/#/?feature=57
+ """
+ pytest.mark.features(feature_id=57)(test_object)
+ return test_object
+
+ @staticmethod
+ def client_split_by_domain_service_host(test_object):
+ """
+ Client Split by domain/service/host
+
+ https://feature-parity.us1.prod.dog/#/?feature=58
+ """
+ pytest.mark.features(feature_id=58)(test_object)
+ return test_object
+
+ @staticmethod
+ def horizontal_propagation_of_x_datadog_tags_between_services(test_object):
+ """
+ Horizontal propagation of `x-datadog-tags` between services
+
+ https://feature-parity.us1.prod.dog/#/?feature=59
+ """
+ pytest.mark.features(feature_id=59)(test_object)
+ return test_object
+
+ @staticmethod
+ def vertical_propagation_of_x_datadog_tags_onto_each_chunk_root_span(test_object):
+ """
+ Vertical propagation of `x-datadog-tags` onto each chunk root span.
+
+ https://feature-parity.us1.prod.dog/#/?feature=60
+ """
+ pytest.mark.features(feature_id=60)(test_object)
+ return test_object
+
+ @staticmethod
+ def creation_and_propagation_of_ddpdm(test_object):
+ """
+ Creation and propagation of `_dd.p.dm`
+
+ https://feature-parity.us1.prod.dog/#/?feature=61
+ """
+ pytest.mark.features(feature_id=61)(test_object)
+ return test_object
+
+ @staticmethod
+ def client_side_stats_supported(test_object):
+ """
+ Client side stats supported
+
+ https://feature-parity.us1.prod.dog/#/?feature=62
+ """
+ pytest.mark.features(feature_id=62)(test_object)
+ return test_object
+
+ @staticmethod
+ def client_side_stats_on_by_default(test_object):
+ """
+ Client side stats on by default
+
+ https://feature-parity.us1.prod.dog/#/?feature=63
+ """
+ pytest.mark.features(feature_id=63)(test_object)
+ return test_object
+
+ @staticmethod
+ def instrumentation_telemetry_enabled_by_default(test_object):
+ """
+ Instrumentation Telemetry enabled by default
+
+ https://feature-parity.us1.prod.dog/#/?feature=64
+ """
+ pytest.mark.features(feature_id=64)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_instrumentation_telemetry_enabled_supported(test_object):
+ """
+ DD_INSTRUMENTATION_TELEMETRY_ENABLED supported
+
+ https://feature-parity.us1.prod.dog/#/?feature=65
+ """
+ pytest.mark.features(feature_id=65)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_environment_collected(test_object):
+ """
+ App environment collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=66
+ """
+ pytest.mark.features(feature_id=66)(test_object)
+ return test_object
+
+ @staticmethod
+ def dependencies_collected(test_object):
+ """
+ Dependencies collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=67
+ """
+ pytest.mark.features(feature_id=67)(test_object)
+ return test_object
+
+ @staticmethod
+ def integrations_enabled_collected(test_object):
+ """
+ Integrations enabled collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=68
+ """
+ pytest.mark.features(feature_id=68)(test_object)
+ return test_object
+
+ @staticmethod
+ def tracer_configurations_collected(test_object):
+ """
+ Tracer Configurations collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=69
+ """
+ pytest.mark.features(feature_id=69)(test_object)
+ return test_object
+
+ @staticmethod
+ def heart_beat_collected(test_object):
+ """
+ Heart beat collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=70
+ """
+ pytest.mark.features(feature_id=70)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_close_collected(test_object):
+ """
+ App close collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=71
+ """
+ pytest.mark.features(feature_id=71)(test_object)
+ return test_object
+
+ @staticmethod
+ def redacted_error_logs_collected(test_object):
+ """
+ Redacted Error Logs collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=72
+ """
+ pytest.mark.features(feature_id=72)(test_object)
+ return test_object
+
+ @staticmethod
+ def metrics_collected(test_object):
+ """
+ Metrics collected
+
+ https://feature-parity.us1.prod.dog/#/?feature=73
+ """
+ pytest.mark.features(feature_id=73)(test_object)
+ return test_object
+
+ @staticmethod
+ def api_v2_implemented(test_object):
+ """
+ API V2 Implemented
+
+ https://feature-parity.us1.prod.dog/#/?feature=74
+ """
+ pytest.mark.features(feature_id=74)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_client_configuration_change_event(test_object):
+ """
+ app-client-configuration-change event
+
+ https://feature-parity.us1.prod.dog/#/?feature=75
+ """
+ pytest.mark.features(feature_id=75)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_product_change_event(test_object):
+ """
+ app-product-change event
+
+ https://feature-parity.us1.prod.dog/#/?feature=76
+ """
+ pytest.mark.features(feature_id=76)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_extended_heartbeat_event(test_object):
+ """
+ app-extended-heartbeat event
+
+ https://feature-parity.us1.prod.dog/#/?feature=77
+ """
+ pytest.mark.features(feature_id=77)(test_object)
+ return test_object
+
+ @staticmethod
+ def message_batch(test_object):
+ """
+ message-batch
+
+ https://feature-parity.us1.prod.dog/#/?feature=78
+ """
+ pytest.mark.features(feature_id=78)(test_object)
+ return test_object
+
+ @staticmethod
+ def app_started_changes(test_object):
+ """
+ app-started changes
+
+ https://feature-parity.us1.prod.dog/#/?feature=79
+ """
+ pytest.mark.features(feature_id=79)(test_object)
+ return test_object
+
+ @staticmethod
+ def dd_telemetry_dependency_collection_enabled_supported(test_object):
+ """
+ DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED supported
+
+ https://feature-parity.us1.prod.dog/#/?feature=80
+ """
+ pytest.mark.features(feature_id=80)(test_object)
+ return test_object
+
+ @staticmethod
+ def additional_http_headers_supported(test_object):
+ """
+ Additional HTTP Headers supported
+
+ https://feature-parity.us1.prod.dog/#/?feature=81
+ """
+ pytest.mark.features(feature_id=81)(test_object)
+ return test_object
+
+ @staticmethod
+ def remote_config_object_supported(test_object):
+ """
+ remote-config object supported
+
+ https://feature-parity.us1.prod.dog/#/?feature=82
+ """
+ pytest.mark.features(feature_id=82)(test_object)
+ return test_object
+
+ @staticmethod
+ def w3c_headers_injection_and_extraction(test_object):
+ """
+ W3C headers injection and extraction
+
+ https://feature-parity.us1.prod.dog/#/?feature=83
+ """
+ pytest.mark.features(feature_id=83)(test_object)
+ return test_object
+
+ @staticmethod
+ def otel_api(test_object):
+ """
+ OTel API
+
+ https://feature-parity.us1.prod.dog/#/?feature=84
+ """
+ pytest.mark.features(feature_id=84)(test_object)
+ return test_object
+
+ @staticmethod
+ def trace_id_128_bit_generation_propagation(test_object):
+ """
+ 128-bit trace id generation + propagation
+
+ https://feature-parity.us1.prod.dog/#/?feature=85
+ """
+ pytest.mark.features(feature_id=85)(test_object)
+ return test_object
+
+ @staticmethod
+ def span_events(test_object):
+ """
+ Span Events
+
+ https://feature-parity.us1.prod.dog/#/?feature=86
+ """
+ pytest.mark.features(feature_id=86)(test_object)
+ return test_object
+
+ @staticmethod
+ def span_links(test_object):
+ """
+ Span Links
+
+ https://feature-parity.us1.prod.dog/#/?feature=87
+ """
+ pytest.mark.features(feature_id=87)(test_object)
+ return test_object
+
+ @staticmethod
+ def client_ip_adress_collection_dd_trace_client_ip_enabled(test_object):
+ """
+ Client IP adress collection (DD_TRACE_CLIENT_IP_ENABLED)
+
+ https://feature-parity.us1.prod.dog/#/?feature=88
+ """
+ pytest.mark.features(feature_id=88)(test_object)
+ return test_object
+
+ @staticmethod
+ def host_auto_instrumentation(test_object):
+ """
+ Host auto-instrumentation
+
+ https://feature-parity.us1.prod.dog/#/?feature=89
+ """
+ pytest.mark.features(feature_id=89)(test_object)
+ return test_object
+
+ @staticmethod
+ def container_auto_instrumentation(test_object):
+ """
+ Container auto-instrumentation
+
+ https://feature-parity.us1.prod.dog/#/?feature=90
+ """
+ pytest.mark.features(feature_id=90)(test_object)
+ return test_object
+
+ @staticmethod
+ def collect_http_post_data_and_headers(test_object):
+ """
+ Collect HTTP Post Data and Headers
+
+ https://feature-parity.us1.prod.dog/#/?feature=94
+ """
+ pytest.mark.features(feature_id=94)(test_object)
+ return test_object
+
+ @staticmethod
+ def weak_hash_vulnerability_detection(test_object):
+ """
+ Weak hash vulnerability detection
+
+ https://feature-parity.us1.prod.dog/#/?feature=96
+ """
+ pytest.mark.features(feature_id=96)(test_object)
+ return test_object
+
+ @staticmethod
+ def db_integrations(test_object):
+ """
+ DB Integrations
+
+ https://feature-parity.us1.prod.dog/#/?feature=98
+ """
+ pytest.mark.features(feature_id=98)(test_object)
+ return test_object
+
+ @staticmethod
+ def http_threats_management(test_object):
+ """
+ HTTP Threats Management
+
+ https://feature-parity.us1.prod.dog/#/?feature=99
+ """
+ pytest.mark.features(feature_id=99)(test_object)
+ return test_object
+
+ @staticmethod
+ def weak_cipher_detection(test_object):
+ """
+ Weak cipher detection
+
+ https://feature-parity.us1.prod.dog/#/?feature=100
+ """
+ pytest.mark.features(feature_id=100)(test_object)
+ return test_object
+
+ @staticmethod
+ def threats_alpha_preview(test_object):
+ """
+ Threats Alpha Preview
+
+ https://feature-parity.us1.prod.dog/#/?feature=110
+ """
+ pytest.mark.features(feature_id=110)(test_object)
+ return test_object
+
+ @staticmethod
+ def procedure_to_debug_install(test_object):
+ """
+ Procedure to debug install
+
+ https://feature-parity.us1.prod.dog/#/?feature=113
+ """
+ pytest.mark.features(feature_id=113)(test_object)
+ return test_object
+
+ @staticmethod
+ def security_events_metadata(test_object):
+ """
+ Security Events Metadata
+
+ https://feature-parity.us1.prod.dog/#/?feature=124
+ """
+ pytest.mark.features(feature_id=124)(test_object)
+ return test_object
+
+ @staticmethod
+ def rate_limiter(test_object):
+ """
+ Rate limiter
+
+ https://feature-parity.us1.prod.dog/#/?feature=134
+ """
+ pytest.mark.features(feature_id=134)(test_object)
+ return test_object
+
+ @staticmethod
+ def support_in_app_waf_metrics_report(test_object):
+ """
+ Support In-App WAF metrics report
+
+ https://feature-parity.us1.prod.dog/#/?feature=140
+ """
+ pytest.mark.features(feature_id=140)(test_object)
+ return test_object
+
+ @staticmethod
+ def user_monitoring(test_object):
+ """
+ User Monitoring
+
+ https://feature-parity.us1.prod.dog/#/?feature=141
+ """
+ pytest.mark.features(feature_id=141)(test_object)
+ return test_object
+
+ @staticmethod
+ def serialize_waf_rules_without_limiting_their_sizes(test_object):
+ """
+ Serialize WAF rules without limiting their sizes
+
+ https://feature-parity.us1.prod.dog/#/?feature=142
+ """
+ pytest.mark.features(feature_id=142)(test_object)
+ return test_object
+
+ @staticmethod
+ def threats_configuration(test_object):
+ """
+ Threats Configuration
+
+ https://feature-parity.us1.prod.dog/#/?feature=143
+ """
+ pytest.mark.features(feature_id=143)(test_object)
+ return test_object
+
+ @staticmethod
+ def sensitive_data_obfuscation(test_object):
+ """
+ Sensitive Data Obfuscation
+
+ https://feature-parity.us1.prod.dog/#/?feature=144
+ """
+ pytest.mark.features(feature_id=144)(test_object)
+ return test_object
+
+ @staticmethod
+ def propagation_of_user_id_rfc(test_object):
+ """
+ Propagation of user Id RFC
+
+ https://feature-parity.us1.prod.dog/#/?feature=146
+ """
+ pytest.mark.features(feature_id=146)(test_object)
+ return test_object
+
+ @staticmethod
+ def appsec_onboarding(test_object):
+ """
+ Onboarding
+
+ https://feature-parity.us1.prod.dog/#/?feature=154
+ """
+ pytest.mark.features(feature_id=154)(test_object)
+ return test_object
+
+ @staticmethod
+ def deactivate_rules_using_rc(test_object):
+ """
+ Deactivate rules using RC
+
+ https://feature-parity.us1.prod.dog/#/?feature=157
+ """
+ pytest.mark.features(feature_id=157)(test_object)
+ return test_object
+
+ @staticmethod
+ def appsec_shell_execution_tracing(test_object):
+ """
+ Shell execution tracing
+
+ https://feature-parity.us1.prod.dog/#/?feature=158
+ """
+ pytest.mark.features(feature_id=158)(test_object)
+ return test_object
+
+ @staticmethod
+ def appsec_userid_blocking(test_object):
+ """
+ UserId Blocking
+
+ https://feature-parity.us1.prod.dog/#/?feature=160
+ """
+ pytest.mark.features(feature_id=160)(test_object)
+ return test_object
+
+ @staticmethod
+ def custom_business_logic_events(test_object):
+ """
+ Custom Business Logic Events
+
+ https://feature-parity.us1.prod.dog/#/?feature=161
+ """
+ pytest.mark.features(feature_id=161)(test_object)
+ return test_object
+
+ @staticmethod
+ def graphql_threats_detection(test_object):
+ """
+ GraphQL Threats Detection
+
+ https://feature-parity.us1.prod.dog/#/?feature=162
+ """
+ pytest.mark.features(feature_id=162)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_sink_sql_injection(test_object):
+ """
+ IAST Sink: SQL Injection
+
+ https://feature-parity.us1.prod.dog/#/?feature=165
+ """
+ pytest.mark.features(feature_id=165)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_sink_command_injection(test_object):
+ """
+ IAST Sink: Command Injection
+
+ https://feature-parity.us1.prod.dog/#/?feature=166
+ """
+ pytest.mark.features(feature_id=166)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_sink_path_traversal(test_object):
+ """
+ IAST Sink: Path Traversal
+
+ https://feature-parity.us1.prod.dog/#/?feature=167
+ """
+ pytest.mark.features(feature_id=167)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_sink_ldap_injection(test_object):
+ """
+ IAST Sink: LDAP Injection
+
+ https://feature-parity.us1.prod.dog/#/?feature=168
+ """
+ pytest.mark.features(feature_id=168)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_request_parameter_value(test_object):
+ """
+ IAST Source: Request Parameter Value
+
+ https://feature-parity.us1.prod.dog/#/?feature=169
+ """
+ pytest.mark.features(feature_id=169)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_request_parameter_name(test_object):
+ """
+ IAST Source: Request Parameter Name
+
+ https://feature-parity.us1.prod.dog/#/?feature=170
+ """
+ pytest.mark.features(feature_id=170)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_header_value(test_object):
+ """
+ IAST Source: Header Value
+
+ https://feature-parity.us1.prod.dog/#/?feature=171
+ """
+ pytest.mark.features(feature_id=171)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_header_name(test_object):
+ """
+ IAST Source: Header Name
+
+ https://feature-parity.us1.prod.dog/#/?feature=172
+ """
+ pytest.mark.features(feature_id=172)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_cookie_value(test_object):
+ """
+ IAST Source: Cookie Value
+
+ https://feature-parity.us1.prod.dog/#/?feature=173
+ """
+ pytest.mark.features(feature_id=173)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_cookie_name(test_object):
+ """
+ IAST Source: Cookie Name
+
+ https://feature-parity.us1.prod.dog/#/?feature=174
+ """
+ pytest.mark.features(feature_id=174)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_source_body(test_object):
+ """
+ IAST Source: Body
+
+ https://feature-parity.us1.prod.dog/#/?feature=175
+ """
+ pytest.mark.features(feature_id=175)(test_object)
+ return test_object
+
+ @staticmethod
+ def grpc_threats_management(test_object):
+ """
+ gRPC Threats Management
+
+ https://feature-parity.us1.prod.dog/#/?feature=176
+ """
+ pytest.mark.features(feature_id=176)(test_object)
+ return test_object
+
+ @staticmethod
+ def telemetry(test_object):
+ """
+ Telemetry
+
+ https://feature-parity.us1.prod.dog/#/?feature=178
+ """
+ pytest.mark.features(feature_id=178)(test_object)
+ return test_object
+
+ @staticmethod
+ def kafkaspan_creationcontext_propagation_with_dd_trace_py(test_object):
+ """
+ [Kafka][Span Creation][Context Propagation] with dd-trace-py
+
+ https://feature-parity.us1.prod.dog/#/?feature=192
+ """
+ pytest.mark.features(feature_id=192)(test_object)
+ return test_object
+
+ @staticmethod
+ def open_tracing_api(test_object):
+ """
+ Open Tracing API
+
+ https://feature-parity.us1.prod.dog/#/?feature=196
+ """
+ pytest.mark.features(feature_id=196)(test_object)
+ return test_object
+
+ @staticmethod
+ def custom_tracing_api(test_object):
+ """
+ Custom Tracing API
+
+ https://feature-parity.us1.prod.dog/#/?feature=197
+ """
+ pytest.mark.features(feature_id=197)(test_object)
+ return test_object
+
+ @staticmethod
+ def iast_sink_hardcoded_secrets(test_object):
+ """
+ IAST sink: Hardcoded secrets detection
+
+ https://feature-parity.us1.prod.dog/#/?feature=198
+ """
+ pytest.mark.features(feature_id=198)(test_object)
+ return test_object
diff --git a/utils/scripts/update_features.py b/utils/scripts/update_features.py
new file mode 100644
index 00000000000..b03ad9e4a82
--- /dev/null
+++ b/utils/scripts/update_features.py
@@ -0,0 +1,49 @@
+import requests
+
+from utils import features
+
+
+def get_known_features():
+ """ return an object feature_id -> attribute name in features decorator """
+ result = {}
+
+ for attr in dir(features):
+ if attr.startswith("__"):
+ continue
+
+ def obj():
+ pass
+
+ obj = getattr(features, attr)(obj)
+
+ if hasattr(obj, "pytestmark"):
+ result[obj.pytestmark[0].kwargs["feature_id"]] = attr
+
+ return result
+
+
+def _main():
+ known_features = get_known_features()
+
+ data = requests.get("https://dd-feature-parity.azurewebsites.net/Import/Features", timeout=10).json()
+ for feature in data:
+ feature_id = feature["id"]
+ if feature_id not in known_features:
+ docstring = f"""
+ {feature['name']}
+
+ https://feature-parity.us1.prod.dog/#/?feature={feature_id}"""
+ print(
+ f"""
+ @staticmethod
+ def {feature['codeSafeName'].lower()}(test_object):
+ ""\"{docstring}
+ ""\"
+ pytest.mark.features(feature_id={feature_id})(test_object)
+ return test_object
+"""
+ )
+
+
+if __name__ == "__main__":
+ _main()