Skip to content

Commit

Permalink
SCA + Appsec Standalone (#3436)
Browse files Browse the repository at this point in the history
Co-authored-by: Charles de Beauchesne <[email protected]>
  • Loading branch information
iunanua and cbeauchesne authored Nov 22, 2024
1 parent 86f272e commit c9bf44a
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/run-end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ jobs:
- name: Run IAST_STANDALONE scenario
if: always() && steps.build.outcome == 'success' && contains(inputs.scenarios, '"IAST_STANDALONE"')
run: ./run.sh IAST_STANDALONE
- name: Run SCA_STANDALONE scenario
if: always() && steps.build.outcome == 'success' && contains(inputs.scenarios, '"SCA_STANDALONE"')
run: ./run.sh SCA_STANDALONE
- name: Run IAST_DEDUPLICATION scenario
if: always() && steps.build.outcome == 'success' && contains(inputs.scenarios, '"IAST_DEDUPLICATION"')
run: ./run.sh IAST_DEDUPLICATION
Expand Down
1 change: 1 addition & 0 deletions manifests/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ tests/:
test_asm_standalone.py:
Test_AppSecStandalone_UpstreamPropagation: v2.55.0
Test_IastStandalone_UpstreamPropagation: v2.55.0
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events: irrelevant (was v2.53.0 but will be replaced by V2)
Test_Login_Events_Extended: irrelevant (was v2.53.0 but will be replaced by V2)
Expand Down
1 change: 1 addition & 0 deletions manifests/golang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ tests/:
test_asm_standalone.py:
Test_AppSecStandalone_UpstreamPropagation: missing_feature
Test_IastStandalone_UpstreamPropagation: missing_feature
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events: missing_feature
Test_Login_Events_Extended: missing_feature
Expand Down
1 change: 1 addition & 0 deletions manifests/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ tests/:
Test_IastStandalone_UpstreamPropagation:
'*': v1.36.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events: irrelevant (was v1.36.0 but will be replaced by V2)
Test_Login_Events_Extended: irrelevant (was v1.36.0 but will be replaced by V2)
Expand Down
3 changes: 3 additions & 0 deletions manifests/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ tests/:
test_asm_standalone.py:
Test_AppSecStandalone_UpstreamPropagation: *ref_5_18_0
Test_IastStandalone_UpstreamPropagation: missing_feature # was supposed to be released in 5.18.0
Test_SCAStandalone_Telemetry:
'*': *ref_5_18_0
nextjs: missing_feature
test_automated_login_events.py:
Test_Login_Events:
'*': *ref_4_4_0
Expand Down
1 change: 1 addition & 0 deletions manifests/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ tests/:
test_asm_standalone.py:
Test_AppSecStandalone_UpstreamPropagation: missing_feature
Test_IastStandalone_UpstreamPropagation: missing_feature
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events: irrelevant (was v0.89.0 but will be replaced by V2)
Test_Login_Events_Extended: irrelevant (was v0.89.0 but will be replaced by V2)
Expand Down
1 change: 1 addition & 0 deletions manifests/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ tests/:
'*': v2.12.3
uwsgi-poc: flaky (APPSEC-55222)
Test_IastStandalone_UpstreamPropagation: missing_feature
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events: irrelevant (was v2.10.0 but will be replaced by V2)
Test_Login_Events_Extended: irrelevant (was v2.10.0 but will be replaced by V2)
Expand Down
1 change: 1 addition & 0 deletions manifests/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ tests/:
test_asm_standalone.py:
Test_AppSecStandalone_UpstreamPropagation: v2.4.1-dev
Test_IastStandalone_UpstreamPropagation: missing_feature
Test_SCAStandalone_Telemetry: missing_feature
test_automated_login_events.py:
Test_Login_Events:
'*': v1.13.0
Expand Down
65 changes: 64 additions & 1 deletion tests/appsec/test_asm_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from requests.structures import CaseInsensitiveDict

from utils import weblog, interfaces, scenarios, features, rfc, bug, flaky
from utils.telemetry_utils import TelemetryUtils
from utils import context, weblog, interfaces, scenarios, features, rfc, bug, flaky


class AsmStandalone_UpstreamPropagation_Base:
Expand Down Expand Up @@ -667,3 +668,65 @@ def test_no_appsec_upstream__no_asm_event__is_kept_with_priority_1__from_1(self)
@bug(library="java", weblog_variant="play", reason="APPSEC-55552")
def test_no_appsec_upstream__no_asm_event__is_kept_with_priority_1__from_2(self):
super().test_no_appsec_upstream__no_asm_event__is_kept_with_priority_1__from_2()


@rfc("https://docs.google.com/document/d/12NBx-nD-IoQEMiCRnJXneq4Be7cbtSc6pJLOFUWTpNE/edit")
@features.sca_standalone
@scenarios.sca_standalone
class Test_SCAStandalone_Telemetry:
"""Tracer correctly propagates SCA telemetry in distributing tracing."""

def assert_standalone_is_enabled(self, request):
# test standalone is enabled and dropping traces
for data, _trace, span in interfaces.library.get_spans(request):
assert span["metrics"]["_sampling_priority_v1"] <= 0
assert span["metrics"]["_dd.apm.enabled"] == 0

def setup_telemetry_sca_enabled_propagated(self):
self.r = weblog.get("/")

def test_telemetry_sca_enabled_propagated(self):
self.assert_standalone_is_enabled(self.r)

for data in interfaces.library.get_telemetry_data():
content = data["request"]["content"]
if content.get("request_type") != "app-started":
continue
configuration = content["payload"]["configuration"]

configuration_by_name = {item["name"]: item for item in configuration}

assert configuration_by_name

DD_APPSEC_SCA_ENABLED = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)

cfg_appsec_enabled = configuration_by_name.get(DD_APPSEC_SCA_ENABLED)
assert cfg_appsec_enabled is not None, "Missing telemetry config item for '{}'".format(DD_APPSEC_SCA_ENABLED)

outcome_value = True
if context.library == "java":
outcome_value = str(outcome_value).lower()
assert cfg_appsec_enabled.get("value") == outcome_value

def setup_app_dependencies_loaded(self):
self.r = weblog.get("/load_dependency")

def test_app_dependencies_loaded(self):
self.assert_standalone_is_enabled(self.r)

seen_loaded_dependencies = TelemetryUtils.get_loaded_dependency(context.library.library)

for data in interfaces.library.get_telemetry_data():
content = data["request"]["content"]
if content.get("request_type") != "app-dependencies-loaded":
continue

for dependency in content["payload"]["dependencies"]:
dependency_id = dependency["name"] # +dependency["version"]

if dependency_id in seen_loaded_dependencies:
seen_loaded_dependencies[dependency_id] = True

for dependency, seen in seen_loaded_dependencies.items():
if not seen:
raise Exception(dependency + " not received in app-dependencies-loaded message")
16 changes: 3 additions & 13 deletions tests/parametric/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import pytest

from utils.telemetry_utils import TelemetryUtils
from utils import context, scenarios, rfc, features, missing_feature, bug


Expand Down Expand Up @@ -544,17 +545,6 @@ def get_app_started_configuration_by_name(test_agent, test_library):

return None

@staticmethod
def get_dd_appsec_sca_enabled_str(library):
DD_APPSEC_SCA_ENABLED = "DD_APPSEC_SCA_ENABLED"
if library == "java":
DD_APPSEC_SCA_ENABLED = "appsec_sca_enabled"
elif library == "nodejs":
DD_APPSEC_SCA_ENABLED = "appsec.sca.enabled"
elif library in ("php", "ruby"):
DD_APPSEC_SCA_ENABLED = "appsec.sca_enabled"
return DD_APPSEC_SCA_ENABLED

@pytest.mark.parametrize(
"library_env, specific_libraries_support, outcome_value",
[
Expand All @@ -577,7 +567,7 @@ def test_telemetry_sca_enabled_propagated(

configuration_by_name = self.get_app_started_configuration_by_name(test_agent, test_library)

DD_APPSEC_SCA_ENABLED = self.get_dd_appsec_sca_enabled_str(context.library)
DD_APPSEC_SCA_ENABLED = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)

cfg_appsec_enabled = configuration_by_name.get(DD_APPSEC_SCA_ENABLED)
assert cfg_appsec_enabled is not None, "Missing telemetry config item for '{}'".format(DD_APPSEC_SCA_ENABLED)
Expand All @@ -594,7 +584,7 @@ def test_telemetry_sca_enabled_propagated(
def test_telemetry_sca_enabled_not_propagated(self, library_env, test_agent, test_library):
configuration_by_name = self.get_app_started_configuration_by_name(test_agent, test_library)

DD_APPSEC_SCA_ENABLED = self.get_dd_appsec_sca_enabled_str(context.library)
DD_APPSEC_SCA_ENABLED = TelemetryUtils.get_dd_appsec_sca_enabled_str(context.library)

if context.library in ("java", "nodejs", "python"):
cfg_appsec_enabled = configuration_by_name.get(DD_APPSEC_SCA_ENABLED)
Expand Down
12 changes: 12 additions & 0 deletions utils/_context/_scenarios/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,18 @@ def all_endtoend_scenarios(test_object):
scenario_groups=[ScenarioGroup.APPSEC],
)

sca_standalone = EndToEndScenario(
"SCA_STANDALONE",
weblog_env={
"DD_APPSEC_ENABLED": "false",
"DD_APPSEC_SCA_ENABLED": "true",
"DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED": "true",
"DD_IAST_ENABLED": "false",
},
doc="SCA standalone mode (APM opt out)",
scenario_groups=[ScenarioGroup.APPSEC],
)

iast_deduplication = EndToEndScenario(
"IAST_DEDUPLICATION",
weblog_env={
Expand Down
10 changes: 10 additions & 0 deletions utils/_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,16 @@ def iast_standalone(test_object):
pytest.mark.features(feature_id=319)(test_object)
return test_object

@staticmethod
def sca_standalone(test_object):
"""
SCA Standalone Billing
https://feature-parity.us1.prod.dog/#/?feature=320
"""
pytest.mark.features(feature_id=320)(test_object)
return test_object

@staticmethod
def host_auto_installation_script_profiling(test_object):
"""
Expand Down
23 changes: 23 additions & 0 deletions utils/telemetry_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class TelemetryUtils:

test_loaded_dependencies = {
"dotnet": {"NodaTime": False},
"nodejs": {"glob": False},
"java": {"httpclient": False},
"ruby": {"bundler": False},
}

@staticmethod
def get_loaded_dependency(library):
return TelemetryUtils.test_loaded_dependencies[library]

@staticmethod
def get_dd_appsec_sca_enabled_str(library):
DD_APPSEC_SCA_ENABLED = "DD_APPSEC_SCA_ENABLED"
if library == "java":
DD_APPSEC_SCA_ENABLED = "appsec_sca_enabled"
elif library == "nodejs":
DD_APPSEC_SCA_ENABLED = "appsec.sca.enabled"
elif library in ("php", "ruby"):
DD_APPSEC_SCA_ENABLED = "appsec.sca_enabled"
return DD_APPSEC_SCA_ENABLED

0 comments on commit c9bf44a

Please sign in to comment.