diff --git a/manifests/python_lambda.yml b/manifests/python_lambda.yml index ef76c50362c..3affdc315bf 100644 --- a/manifests/python_lambda.yml +++ b/manifests/python_lambda.yml @@ -266,7 +266,7 @@ manifest: tests/appsec/test_reports.py::Test_Info: v7.112.0 tests/appsec/test_reports.py::Test_RequestHeaders: v7.112.0 tests/appsec/test_reports.py::Test_StatusCode: v7.112.0 - tests/appsec/test_sca_reachability.py: incomplete_test_app (Lambda SCA dependency fixtures and vulnerable-call endpoints are not implemented) + tests/appsec/test_sca_reachability.py: missing_feature (requires Lambda SCA reachability support in dd-trace-py and datadog-lambda-python) tests/appsec/test_trace_tagging.py::Test_TraceTaggingRules: v8.113.0 tests/appsec/test_traces.py::Test_AppSecEventSpanTags: v7.112.0 tests/appsec/test_traces.py::Test_AppSecEventSpanTags::test_header_collection: bug (APPSEC-58202) diff --git a/tests/appsec/sca_advisories.json b/tests/appsec/sca_advisories.json new file mode 100644 index 00000000000..186d812b022 --- /dev/null +++ b/tests/appsec/sca_advisories.json @@ -0,0 +1,26 @@ +{ + "targets": [ + { + "id": "system-tests-sca", + "lang": "python", + "dependency_name": "requests", + "package_versions": [ + ">=0" + ], + "targets": [ + "requests.sessions:Session.send" + ] + }, + { + "id": "system-tests-sca", + "lang": "maven", + "dependency_name": "com.github.junrar:junrar", + "package_versions": [ + ">=0" + ], + "targets": [ + "com.github.junrar:LocalFolderExtractor.createDirectory" + ] + } + ] +} diff --git a/tests/appsec/test_sca_reachability.py b/tests/appsec/test_sca_reachability.py index aef5a54ef42..e494e3eddfc 100644 --- a/tests/appsec/test_sca_reachability.py +++ b/tests/appsec/test_sca_reachability.py @@ -33,6 +33,12 @@ "path": "com.datadoghq.system_tests.springboot.ScaReachability", "symbol": "junrarHit", }, + "python_lambda": { + "cve_id": ["system-tests-sca"], + "vulnerable_dep": "requests", + "path": "handler.py", + "symbol": "sca_requests_vulnerable_call", + }, "java_lambda": { "cve_id": ["GHSA-hf5p-q87m-crj7"], "vulnerable_dep": "junrar", diff --git a/utils/_context/_scenarios/aws_lambda.py b/utils/_context/_scenarios/aws_lambda.py index 30919185d00..4a0aad1a59f 100644 --- a/utils/_context/_scenarios/aws_lambda.py +++ b/utils/_context/_scenarios/aws_lambda.py @@ -215,7 +215,11 @@ class AppsecLambdaSca(_LambdaScenario): def __init__(self) -> None: super().__init__( "APPSEC_LAMBDA_SCA", - weblog_env={"DD_APPSEC_ENABLED": "false", "DD_APPSEC_SCA_ENABLED": "true"}, + weblog_env={ + "DD_APPSEC_ENABLED": "false", + "DD_APPSEC_SCA_ENABLED": "true", + }, + weblog_volumes={"./tests/appsec/sca_advisories.json": {"bind": "/sca_advisories.json", "mode": "ro"}}, doc="SCA dependency metadata and runtime reachability in Lambda with AppSec disabled", scenario_groups=[scenario_groups.appsec, scenario_groups.appsec_lambda], ) diff --git a/utils/build/docker/python_lambda/function/app.sh b/utils/build/docker/python_lambda/function/app.sh index eb958bd98f3..96c28071310 100644 --- a/utils/build/docker/python_lambda/function/app.sh +++ b/utils/build/docker/python_lambda/function/app.sh @@ -4,6 +4,22 @@ set -eu export DD_LAMBDA_HANDLER=handler.lambda_handler +# Only the SCA scenario mounts this catalog. Install its Python entries before +# starting the Lambda wrapper, which initializes reachability instrumentation. +if [ -f /sca_advisories.json ]; then + python3 - <<'PY' +import json +from pathlib import Path + +catalog = json.loads(Path("/sca_advisories.json").read_text()) +targets = [entry for entry in catalog["targets"] if entry["lang"] == "python"] +data_paths = list(Path("/opt/python").glob("lib/python*/site-packages/ddtrace/appsec/sca/_cve_data.json")) +if len(data_paths) != 1: + raise RuntimeError(f"Expected one bundled SCA catalog, found {data_paths}") +data_paths[0].write_text(json.dumps({"targets": targets})) +PY +fi + socat TCP-LISTEN:8127,reuseaddr,fork,bind=0.0.0.0 TCP:127.0.0.1:8126 & exec /lambda-entrypoint.sh datadog_lambda.handler.handler diff --git a/utils/build/docker/python_lambda/function/handler.py b/utils/build/docker/python_lambda/function/handler.py index d507f927a20..875f4be39e4 100644 --- a/utils/build/docker/python_lambda/function/handler.py +++ b/utils/build/docker/python_lambda/function/handler.py @@ -47,6 +47,28 @@ _TRACK_CUSTOM_APPSEC_EVENT_NAME = "system_tests_appsec_event" +@app.get("/sca/vulnerable-call") +def sca_requests_vulnerable_call() -> str: + """Exercise the synthetic advisory's Session.send target.""" + with requests.Session() as session: + try: + session.send(requests.Request("GET", "http://127.0.0.1:1").prepare(), timeout=1) + except requests.exceptions.ConnectionError: + pass + return "OK" + + +@app.get("/sca/vulnerable-call-alt") +def sca_requests_vulnerable_call_alt() -> str: + """Use a distinct caller for the same target to check first-hit deduplication.""" + with requests.Session() as session: + try: + session.send(requests.Request("GET", "http://127.0.0.1:1").prepare(), timeout=1) + except requests.exceptions.ConnectionError: + pass + return "OK" + + def version_info(): return { "status": "ok", diff --git a/utils/scripts/libraries_and_scenarios_rules.yml b/utils/scripts/libraries_and_scenarios_rules.yml index 806149e4c5d..31f60a3c861 100644 --- a/utils/scripts/libraries_and_scenarios_rules.yml +++ b/utils/scripts/libraries_and_scenarios_rules.yml @@ -589,7 +589,12 @@ patterns: tests/appsec/test_sca_reachability.py: scenario_groups: null - libraries: [java, java_lambda, python] + libraries: [java, java_lambda, python, python_lambda] + + tests/appsec/sca_advisories.json: + scenario_groups: null + scenarios: [APPSEC_LAMBDA_SCA] + libraries: python_lambda ################################# Default rules ################################ # The rules in this section are only applied if no other rule is applicable.