Skip to content

feat(sca): runtime SCA reachability#17156

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 39 commits intomainfrom
avara1986/sca-telemetry-rereporting-and-module
Apr 17, 2026
Merged

feat(sca): runtime SCA reachability#17156
gh-worker-dd-mergequeue-cf854d[bot] merged 39 commits intomainfrom
avara1986/sca-telemetry-rereporting-and-module

Conversation

@avara1986
Copy link
Copy Markdown
Member

@avara1986 avara1986 commented Mar 27, 2026

Description

Implements Runtime SCA Reachability — the tracer reports which vulnerable symbols (functions/methods in third-party libraries with known CVEs) have actually been invoked at runtime, reducing false positives from static SCA analysis.

RFC: https://docs.google.com/document/d/1xDw9iG6h41VCEgJGTqoJdruRaNS4pYgNifO6nhiizWA/edit?tab=t.a9gurws0d8ua

How it works

When DD_APPSEC_SCA_ENABLED=true:

  1. CVE data loading — At tracer startup, reads _cve_data.json containing vulnerability targets (symbol + CVE + version constraint). Filters against installed packages.
  2. Runtime instrumentation — For each applicable CVE target, applies bytecode injection (inject_hook) to the vulnerable function. Supports both eager (already-imported modules) and lazy (via ModuleWatchdog for deferred imports).
  3. CVE registration — Immediately registers all applicable CVEs on their dependencies with reached: [] in the telemetry app-dependencies-loaded payload. The backend knows which CVEs apply before any symbol is hit.
  4. Reachability detection — When an instrumented function executes, the hook captures the caller's file path, method name, and line number, then attaches it to the CVE's reached array. Only the first occurrence is reported per CVE (RFC: "reporting a single occurrence is sufficient").
  5. Telemetry reporting — On each heartbeat (default 60s), dependencies with new reachability data are re-reported with all their metadata via app-dependencies-loaded.

Telemetry payload (RFC v3)

{
  "request_type": "app-dependencies-loaded",
  "payload": {
    "dependencies": [
      {
        "name": "requests",
        "version": "2.31.0",
        "metadata": [
          {
            "type": "reachability",
            "value": "{\"id\":\"CVE-2024-35195\",\"reached\":[{\"path\":\"myapp/views.py\",\"method\":\"handle_request\",\"line\":42}]}"
          }
        ]
      }
    ]
  }
}

Before any symbol is hit, CVEs are reported with "reached":[]. When a symbol executes, the first caller info is added to the reached array.

Performance

Benchmark: scripts/perf_bench_heartbeat_cycles.py

Measures collect_report() execution time per heartbeat cycle under different scenarios. The overhead is paid only in the background telemetry thread (every 60s), never in user request paths.

  • SCA OFF (main): baseline on main branch — old update_imported_dependencies() path, no DependencyTracker, no re-report scan
  • SCA OFF: this branch with DD_APPSEC_SCA_ENABLED=false — new DependencyTracker with metadata=None, re-report scan skipped
  • SCA ON: this branch with DD_APPSEC_SCA_ENABLED=true — new DependencyTracker with metadata=[]
  • Overhead: (SCA ON − SCA OFF) / SCA OFF

1,000 dependencies (typical large application)

Heartbeat Cycle SCA OFF (main) SCA OFF SCA ON Overhead
First heartbeat (all new) 4.56ms 4.63ms 5.10ms +10.1%
Idle (nothing to report) 0.2us 72.2us 239.6us +231.8%
CVE registration (100 CVEs, reached=[]) 0.3us 73.5us 1.20ms +1527.5%
SCA hits (100 hits on 50 deps) 0.3us 73.7us 1.44ms +1857.1%

10,000 dependencies (extreme scale)

Heartbeat Cycle SCA OFF (main) SCA OFF SCA ON Overhead
First heartbeat (all new) 53.15ms 57.18ms 62.12ms +8.6%
Idle (nothing to report) 0.3us 742.6us 2.20ms +195.7%
CVE registration (1,000 CVEs, reached=[]) 0.3us 720.7us 13.51ms +1774.4%
SCA hits (1,000 hits on 500 deps) 0.3us 718.9us 15.56ms +2064.2%

Payload size

Scenario (1,000 deps) Entries Size
First heartbeat SCA OFF 1,000 62 KB
First heartbeat SCA ON 1,000 62 KB
CVE registration (100 CVEs) 50 10 KB
SCA hits (100 hits) 50 16 KB

Memory overhead

Scenario (1,000 deps) SCA OFF SCA ON Delta
Idle heartbeat 155.3 KB 192.5 KB +37.2 KB
CVE registration (100 CVEs) 136.4 KB 205.8 KB +69.4 KB
SCA hits (100 hits) 136.2 KB 208.5 KB +72.3 KB

Note on overhead: The percentage overhead for idle, CVE registration, and SCA hits appears very high because the SCA OFF baseline includes mock/benchmark harness overhead (~72us at 1K deps) that dominates the measurement. In absolute terms:

  • First heartbeat: nearly identical across all three columns (4.56ms → 4.63ms → 5.10ms at 1K deps), confirming the DependencyTracker refactor adds minimal overhead to initial dependency discovery.
  • Idle heartbeat with SCA OFF: ~72us includes benchmark mock overhead; measured independently at ~8us (lock acquisition + get_newly_imported_modules() + lazy config check). The re-report scan is completely skipped when SCA is disabled.
  • SCA ON worst case at 1,000 dependencies: 1.44ms per 60s heartbeat — 0.002% of the cycle.
  • SCA ON worst case at 10,000 dependencies with 1,000 CVEs: 16ms — 0.027% of the heartbeat interval.

All overhead runs entirely in the background telemetry thread and does not affect user request latency.

SLO benchmark

A CI-integrated benchmark suite is available at benchmarks/telemetry_dependencies/ with 8 scenarios covering first/idle/cve/hits phases at 100 and 1,000 dependencies. It is triggered automatically when ddtrace/internal/telemetry/dependency*.py or ddtrace/appsec/sca/* files change and compares performance between the base branch and this PR.

Risks

  • Bytecode injection: Uses the existing inject_hook infrastructure from dd-trace-py. The hook is exception-safe (wrapped in try/except) and never raises in user code.
  • Memory: DependencyEntry objects add ~150 bytes per dependency vs plain strings. At 1,000 deps this is ~150KB total — negligible.
  • Lock contention: The DependencyTracker._lock is held briefly during attach_metadata calls from the SCA hook. After the first hit per CVE (max reached=1), subsequent hook invocations short-circuit before any lock acquisition.

Additional Notes

@cit-pr-commenter-54b7da
Copy link
Copy Markdown

cit-pr-commenter-54b7da Bot commented Mar 27, 2026

Codeowners resolved as

.gitlab/benchmarks/bp-runner.microbenchmarks.fail-on-breach.template.yml  @DataDog/python-guild @DataDog/apm-core-python
.riot/requirements/11335dd.txt                                          @DataDog/apm-python
.riot/requirements/148c37a.txt                                          @DataDog/apm-python
.riot/requirements/176aab2.txt                                          @DataDog/apm-python
.riot/requirements/18269eb.txt                                          @DataDog/apm-python
.riot/requirements/190e5df.txt                                          @DataDog/apm-python
.riot/requirements/1ab3731.txt                                          @DataDog/apm-python
.riot/requirements/1d488a9.txt                                          @DataDog/apm-python
.riot/requirements/1dbdbea.txt                                          @DataDog/apm-python
.riot/requirements/1e5dd1a.txt                                          @DataDog/apm-python
.riot/requirements/42964a4.txt                                          @DataDog/apm-python
.riot/requirements/538bd65.txt                                          @DataDog/apm-python
.riot/requirements/5e2ba1e.txt                                          @DataDog/apm-python
.riot/requirements/76dd566.txt                                          @DataDog/apm-python
.riot/requirements/7c2d6af.txt                                          @DataDog/apm-python
.riot/requirements/848bcfc.txt                                          @DataDog/apm-python
.riot/requirements/a5c98ed.txt                                          @DataDog/apm-python
.riot/requirements/c05715c.txt                                          @DataDog/apm-python
.riot/requirements/dbf2d5f.txt                                          @DataDog/apm-python
.riot/requirements/fcf2285.txt                                          @DataDog/apm-python
benchmarks/suitespec.yml                                                @DataDog/apm-core-python
benchmarks/telemetry_dependencies/config.yaml                           @DataDog/apm-core-python
benchmarks/telemetry_dependencies/scenario.py                           @DataDog/apm-core-python
ddtrace/appsec/_constants.py                                            @DataDog/asm-python
ddtrace/appsec/sca/__init__.py                                          @DataDog/asm-python
ddtrace/appsec/sca/_cve_data.json                                       @DataDog/asm-python
ddtrace/appsec/sca/_cve_loader.py                                       @DataDog/asm-python
ddtrace/appsec/sca/_instrumenter.py                                     @DataDog/asm-python
ddtrace/appsec/sca/_registry.py                                         @DataDog/asm-python
ddtrace/appsec/sca/_resolver.py                                         @DataDog/asm-python
ddtrace/internal/sca/__init__.py                                        @DataDog/apm-core-python
ddtrace/internal/sca/product.py                                         @DataDog/apm-core-python
pyproject.toml                                                          @DataDog/python-guild
riotfile.py                                                             @DataDog/apm-python
scripts/perf_bench_heartbeat_cycles.py                                  @DataDog/apm-core-python
scripts/perf_bench_sca_telemetry.py                                     @DataDog/apm-core-python
setup.py                                                                @DataDog/python-guild
tests/appsec/app.py                                                     @DataDog/asm-python
tests/appsec/architectures/test_appsec_loading_modules.py               @DataDog/asm-python
tests/appsec/integrations/flask_tests/test_sca_flask_testagent.py       @DataDog/asm-python
tests/appsec/sca/__init__.py                                            @DataDog/asm-python
tests/appsec/sca/test_cve_loader.py                                     @DataDog/asm-python
tests/appsec/sca/test_instrumenter.py                                   @DataDog/asm-python
tests/appsec/sca/test_registry.py                                       @DataDog/asm-python
tests/appsec/sca/test_resolver.py                                       @DataDog/asm-python
tests/appsec/suitespec.yml                                              @DataDog/asm-python

@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented Mar 27, 2026

Performance SLOs

Comparing candidate avara1986/sca-telemetry-rereporting-and-module (f4dd6de) with baseline main (a5ca84b)

📈 Performance Regressions (3 suites)
📈 forktime - 4/4

✅ baseline

Time: ✅ 1.933ms (SLO: <3.000ms 📉 -35.6%) vs baseline: +4.9%

Memory: ✅ 29.216MB (SLO: <33.000MB 📉 -11.5%) vs baseline: +4.8%


✅ configured

Time: ✅ 10.209ms (SLO: <17.000ms 📉 -39.9%) vs baseline: 📈 +11.8%

Memory: ✅ 58.453MB (SLO: <60.000MB -2.6%) vs baseline: +5.5%


📈 iastaspects - 118/118

✅ add_aspect

Time: ✅ 103.156µs (SLO: <130.000µs 📉 -20.6%) vs baseline: +1.3%

Memory: ✅ 43.970MB (SLO: <46.000MB -4.4%) vs baseline: +5.4%


✅ add_inplace_aspect

Time: ✅ 100.502µs (SLO: <130.000µs 📉 -22.7%) vs baseline: -4.7%

Memory: ✅ 43.884MB (SLO: <46.000MB -4.6%) vs baseline: +5.5%


✅ add_inplace_noaspect

Time: ✅ 28.256µs (SLO: <40.000µs 📉 -29.4%) vs baseline: +0.3%

Memory: ✅ 43.935MB (SLO: <46.000MB -4.5%) vs baseline: +5.5%


✅ add_noaspect

Time: ✅ 49.422µs (SLO: <70.000µs 📉 -29.4%) vs baseline: +0.7%

Memory: ✅ 43.890MB (SLO: <46.000MB -4.6%) vs baseline: +5.1%


✅ bytearray_aspect

Time: ✅ 250.241µs (SLO: <400.000µs 📉 -37.4%) vs baseline: -9.0%

Memory: ✅ 43.904MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ bytearray_extend_aspect

Time: ✅ 646.268µs (SLO: <800.000µs 📉 -19.2%) vs baseline: -2.4%

Memory: ✅ 43.906MB (SLO: <46.000MB -4.6%) vs baseline: +5.5%


✅ bytearray_extend_noaspect

Time: ✅ 265.667µs (SLO: <400.000µs 📉 -33.6%) vs baseline: -0.3%

Memory: ✅ 43.868MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ bytearray_noaspect

Time: ✅ 139.531µs (SLO: <300.000µs 📉 -53.5%) vs baseline: -3.1%

Memory: ✅ 43.894MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ bytes_aspect

Time: ✅ 219.188µs (SLO: <300.000µs 📉 -26.9%) vs baseline: -6.7%

Memory: ✅ 43.923MB (SLO: <46.000MB -4.5%) vs baseline: +5.1%


✅ bytes_noaspect

Time: ✅ 136.229µs (SLO: <200.000µs 📉 -31.9%) vs baseline: +0.3%

Memory: ✅ 43.989MB (SLO: <46.000MB -4.4%) vs baseline: +5.5%


✅ bytesio_aspect

Time: ✅ 3.787ms (SLO: <5.000ms 📉 -24.3%) vs baseline: -1.6%

Memory: ✅ 43.885MB (SLO: <46.000MB -4.6%) vs baseline: +5.1%


✅ bytesio_noaspect

Time: ✅ 312.390µs (SLO: <420.000µs 📉 -25.6%) vs baseline: -1.4%

Memory: ✅ 43.862MB (SLO: <46.000MB -4.6%) vs baseline: +5.6%


✅ capitalize_aspect

Time: ✅ 88.639µs (SLO: <300.000µs 📉 -70.5%) vs baseline: -0.6%

Memory: ✅ 43.912MB (SLO: <46.000MB -4.5%) vs baseline: +5.4%


✅ capitalize_noaspect

Time: ✅ 248.433µs (SLO: <300.000µs 📉 -17.2%) vs baseline: -3.9%

Memory: ✅ 43.851MB (SLO: <46.000MB -4.7%) vs baseline: +5.1%


✅ casefold_aspect

Time: ✅ 91.736µs (SLO: <500.000µs 📉 -81.7%) vs baseline: +3.0%

Memory: ✅ 43.840MB (SLO: <46.000MB -4.7%) vs baseline: +5.3%


✅ casefold_noaspect

Time: ✅ 306.630µs (SLO: <500.000µs 📉 -38.7%) vs baseline: -2.1%

Memory: ✅ 43.882MB (SLO: <46.000MB -4.6%) vs baseline: +5.0%


✅ decode_aspect

Time: ✅ 87.324µs (SLO: <100.000µs 📉 -12.7%) vs baseline: +0.6%

Memory: ✅ 44.058MB (SLO: <46.000MB -4.2%) vs baseline: +5.8%


✅ decode_noaspect

Time: ✅ 155.159µs (SLO: <210.000µs 📉 -26.1%) vs baseline: +1.0%

Memory: ✅ 44.010MB (SLO: <46.000MB -4.3%) vs baseline: +5.7%


✅ encode_aspect

Time: ✅ 84.865µs (SLO: <200.000µs 📉 -57.6%) vs baseline: -0.4%

Memory: ✅ 43.923MB (SLO: <46.000MB -4.5%) vs baseline: +5.7%


✅ encode_noaspect

Time: ✅ 143.170µs (SLO: <200.000µs 📉 -28.4%) vs baseline: -0.7%

Memory: ✅ 43.961MB (SLO: <46.000MB -4.4%) vs baseline: +5.6%


✅ format_aspect

Time: ✅ 14.595ms (SLO: <19.200ms 📉 -24.0%) vs baseline: ~same

Memory: ✅ 43.986MB (SLO: <46.000MB -4.4%) vs baseline: +5.5%


✅ format_map_aspect

Time: ✅ 16.394ms (SLO: <21.500ms 📉 -23.8%) vs baseline: +0.5%

Memory: ✅ 43.953MB (SLO: <46.000MB -4.4%) vs baseline: +5.2%


✅ format_map_noaspect

Time: ✅ 368.862µs (SLO: <500.000µs 📉 -26.2%) vs baseline: -1.0%

Memory: ✅ 43.913MB (SLO: <46.000MB -4.5%) vs baseline: +5.4%


✅ format_noaspect

Time: ✅ 308.731µs (SLO: <500.000µs 📉 -38.3%) vs baseline: -1.9%

Memory: ✅ 43.905MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ index_aspect

Time: ✅ 122.852µs (SLO: <300.000µs 📉 -59.0%) vs baseline: -4.7%

Memory: ✅ 43.904MB (SLO: <46.000MB -4.6%) vs baseline: +4.9%


✅ index_noaspect

Time: ✅ 40.767µs (SLO: <300.000µs 📉 -86.4%) vs baseline: +0.9%

Memory: ✅ 43.923MB (SLO: <46.000MB -4.5%) vs baseline: +5.0%


✅ join_aspect

Time: ✅ 209.295µs (SLO: <300.000µs 📉 -30.2%) vs baseline: -5.3%

Memory: ✅ 43.854MB (SLO: <46.000MB -4.7%) vs baseline: +5.1%


✅ join_noaspect

Time: ✅ 142.726µs (SLO: <300.000µs 📉 -52.4%) vs baseline: -1.3%

Memory: ✅ 43.915MB (SLO: <46.000MB -4.5%) vs baseline: +5.3%


✅ ljust_aspect

Time: ✅ 498.370µs (SLO: <700.000µs 📉 -28.8%) vs baseline: -3.1%

Memory: ✅ 43.880MB (SLO: <46.000MB -4.6%) vs baseline: +5.5%


✅ ljust_noaspect

Time: ✅ 257.253µs (SLO: <300.000µs 📉 -14.2%) vs baseline: -2.5%

Memory: ✅ 43.903MB (SLO: <46.000MB -4.6%) vs baseline: +5.4%


✅ lower_aspect

Time: ✅ 293.477µs (SLO: <500.000µs 📉 -41.3%) vs baseline: -5.2%

Memory: ✅ 43.901MB (SLO: <46.000MB -4.6%) vs baseline: +5.4%


✅ lower_noaspect

Time: ✅ 234.101µs (SLO: <300.000µs 📉 -22.0%) vs baseline: -1.9%

Memory: ✅ 43.998MB (SLO: <46.000MB -4.4%) vs baseline: +5.9%


✅ lstrip_aspect

Time: ✅ 0.341ms (SLO: <3.000ms 📉 -88.6%) vs baseline: 📈 +23.9%

Memory: ✅ 43.876MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ lstrip_noaspect

Time: ✅ 0.176ms (SLO: <3.000ms 📉 -94.1%) vs baseline: -0.8%

Memory: ✅ 43.948MB (SLO: <46.000MB -4.5%) vs baseline: +5.4%


✅ modulo_aspect

Time: ✅ 14.286ms (SLO: <18.750ms 📉 -23.8%) vs baseline: +0.5%

Memory: ✅ 43.916MB (SLO: <46.000MB -4.5%) vs baseline: +5.3%


✅ modulo_aspect_for_bytearray_bytearray

Time: ✅ 14.680ms (SLO: <19.350ms 📉 -24.1%) vs baseline: -0.5%

Memory: ✅ 44.056MB (SLO: <46.000MB -4.2%) vs baseline: +5.6%


✅ modulo_aspect_for_bytes

Time: ✅ 14.356ms (SLO: <18.900ms 📉 -24.0%) vs baseline: ~same

Memory: ✅ 43.986MB (SLO: <46.000MB -4.4%) vs baseline: +5.1%


✅ modulo_aspect_for_bytes_bytearray

Time: ✅ 14.525ms (SLO: <19.150ms 📉 -24.2%) vs baseline: -0.5%

Memory: ✅ 44.057MB (SLO: <46.000MB -4.2%) vs baseline: +5.6%


✅ modulo_noaspect

Time: ✅ 0.365ms (SLO: <3.000ms 📉 -87.8%) vs baseline: -3.2%

Memory: ✅ 43.969MB (SLO: <46.000MB -4.4%) vs baseline: +5.5%


✅ replace_aspect

Time: ✅ 18.297ms (SLO: <24.000ms 📉 -23.8%) vs baseline: -0.4%

Memory: ✅ 43.926MB (SLO: <46.000MB -4.5%) vs baseline: +5.1%


✅ replace_noaspect

Time: ✅ 304.927µs (SLO: <400.000µs 📉 -23.8%) vs baseline: +7.1%

Memory: ✅ 43.924MB (SLO: <46.000MB -4.5%) vs baseline: +5.2%


✅ repr_aspect

Time: ✅ 323.434µs (SLO: <420.000µs 📉 -23.0%) vs baseline: -4.0%

Memory: ✅ 43.989MB (SLO: <46.000MB -4.4%) vs baseline: +5.1%


✅ repr_noaspect

Time: ✅ 46.787µs (SLO: <90.000µs 📉 -48.0%) vs baseline: -0.4%

Memory: ✅ 43.971MB (SLO: <46.000MB -4.4%) vs baseline: +5.5%


✅ rstrip_aspect

Time: ✅ 378.691µs (SLO: <500.000µs 📉 -24.3%) vs baseline: -2.8%

Memory: ✅ 43.971MB (SLO: <46.000MB -4.4%) vs baseline: +5.3%


✅ rstrip_noaspect

Time: ✅ 184.211µs (SLO: <300.000µs 📉 -38.6%) vs baseline: +1.3%

Memory: ✅ 43.968MB (SLO: <46.000MB -4.4%) vs baseline: +5.4%


✅ slice_aspect

Time: ✅ 183.748µs (SLO: <300.000µs 📉 -38.8%) vs baseline: +1.1%

Memory: ✅ 43.892MB (SLO: <46.000MB -4.6%) vs baseline: +5.2%


✅ slice_noaspect

Time: ✅ 54.027µs (SLO: <90.000µs 📉 -40.0%) vs baseline: +0.5%

Memory: ✅ 43.952MB (SLO: <46.000MB -4.5%) vs baseline: +5.3%


✅ stringio_aspect

Time: ✅ 3.837ms (SLO: <5.000ms 📉 -23.3%) vs baseline: -1.4%

Memory: ✅ 43.845MB (SLO: <46.000MB -4.7%) vs baseline: +5.1%


✅ stringio_noaspect

Time: ✅ 344.602µs (SLO: <500.000µs 📉 -31.1%) vs baseline: -1.6%

Memory: ✅ 43.871MB (SLO: <46.000MB -4.6%) vs baseline: +5.4%


✅ strip_aspect

Time: ✅ 268.187µs (SLO: <350.000µs 📉 -23.4%) vs baseline: -1.5%

Memory: ✅ 43.837MB (SLO: <46.000MB -4.7%) vs baseline: +5.3%


✅ strip_noaspect

Time: ✅ 176.725µs (SLO: <240.000µs 📉 -26.4%) vs baseline: +0.6%

Memory: ✅ 43.903MB (SLO: <46.000MB -4.6%) vs baseline: +5.5%


✅ swapcase_aspect

Time: ✅ 334.933µs (SLO: <500.000µs 📉 -33.0%) vs baseline: -3.2%

Memory: ✅ 43.804MB (SLO: <46.000MB -4.8%) vs baseline: +5.0%


✅ swapcase_noaspect

Time: ✅ 271.614µs (SLO: <400.000µs 📉 -32.1%) vs baseline: -1.5%

Memory: ✅ 44.012MB (SLO: <46.000MB -4.3%) vs baseline: +6.0%


✅ title_aspect

Time: ✅ 318.683µs (SLO: <500.000µs 📉 -36.3%) vs baseline: -6.6%

Memory: ✅ 43.836MB (SLO: <46.000MB -4.7%) vs baseline: +5.2%


✅ title_noaspect

Time: ✅ 258.561µs (SLO: <400.000µs 📉 -35.4%) vs baseline: -2.7%

Memory: ✅ 43.889MB (SLO: <46.000MB -4.6%) vs baseline: +5.4%


✅ translate_aspect

Time: ✅ 561.968µs (SLO: <700.000µs 📉 -19.7%) vs baseline: +9.4%

Memory: ✅ 43.929MB (SLO: <46.000MB -4.5%) vs baseline: +5.4%


✅ translate_noaspect

Time: ✅ 423.278µs (SLO: <500.000µs 📉 -15.3%) vs baseline: -4.4%

Memory: ✅ 43.834MB (SLO: <46.000MB -4.7%) vs baseline: +5.1%


✅ upper_aspect

Time: ✅ 296.922µs (SLO: <500.000µs 📉 -40.6%) vs baseline: -6.3%

Memory: ✅ 43.884MB (SLO: <46.000MB -4.6%) vs baseline: +5.3%


✅ upper_noaspect

Time: ✅ 235.871µs (SLO: <400.000µs 📉 -41.0%) vs baseline: -1.5%

Memory: ✅ 43.928MB (SLO: <46.000MB -4.5%) vs baseline: +5.3%


📈 iastaspectsospath - 24/24

✅ ospathbasename_aspect

Time: ✅ 532.347µs (SLO: <700.000µs 📉 -24.0%) vs baseline: 📈 +23.9%

Memory: ✅ 43.790MB (SLO: <46.000MB -4.8%) vs baseline: +5.3%


✅ ospathbasename_noaspect

Time: ✅ 433.445µs (SLO: <700.000µs 📉 -38.1%) vs baseline: -0.9%

Memory: ✅ 43.858MB (SLO: <46.000MB -4.7%) vs baseline: +5.9%


✅ ospathjoin_aspect

Time: ✅ 625.967µs (SLO: <700.000µs 📉 -10.6%) vs baseline: -1.3%

Memory: ✅ 43.873MB (SLO: <46.000MB -4.6%) vs baseline: +5.3%


✅ ospathjoin_noaspect

Time: ✅ 641.536µs (SLO: <700.000µs -8.4%) vs baseline: -0.7%

Memory: ✅ 43.817MB (SLO: <46.000MB -4.7%) vs baseline: +5.6%


✅ ospathnormcase_aspect

Time: ✅ 350.231µs (SLO: <700.000µs 📉 -50.0%) vs baseline: -1.7%

Memory: ✅ 43.873MB (SLO: <46.000MB -4.6%) vs baseline: +5.8%


✅ ospathnormcase_noaspect

Time: ✅ 361.939µs (SLO: <700.000µs 📉 -48.3%) vs baseline: -0.8%

Memory: ✅ 43.842MB (SLO: <46.000MB -4.7%) vs baseline: +5.7%


✅ ospathsplit_aspect

Time: ✅ 488.035µs (SLO: <700.000µs 📉 -30.3%) vs baseline: -2.8%

Memory: ✅ 43.831MB (SLO: <46.000MB -4.7%) vs baseline: +5.6%


✅ ospathsplit_noaspect

Time: ✅ 500.795µs (SLO: <700.000µs 📉 -28.5%) vs baseline: -1.6%

Memory: ✅ 43.868MB (SLO: <46.000MB -4.6%) vs baseline: +6.0%


✅ ospathsplitdrive_aspect

Time: ✅ 372.275µs (SLO: <700.000µs 📉 -46.8%) vs baseline: -2.8%

Memory: ✅ 43.812MB (SLO: <46.000MB -4.8%) vs baseline: +5.5%


✅ ospathsplitdrive_noaspect

Time: ✅ 72.699µs (SLO: <700.000µs 📉 -89.6%) vs baseline: -1.2%

Memory: ✅ 43.823MB (SLO: <46.000MB -4.7%) vs baseline: +5.6%


✅ ospathsplitext_aspect

Time: ✅ 470.324µs (SLO: <700.000µs 📉 -32.8%) vs baseline: +1.3%

Memory: ✅ 43.771MB (SLO: <46.000MB -4.8%) vs baseline: +5.5%


✅ ospathsplitext_noaspect

Time: ✅ 471.936µs (SLO: <700.000µs 📉 -32.6%) vs baseline: -0.1%

Memory: ✅ 43.843MB (SLO: <46.000MB -4.7%) vs baseline: +5.6%

🟡 Near SLO Breach (7 suites)
🟡 djangosimple - 28/28

✅ appsec

Time: ✅ 19.704ms (SLO: <22.300ms 📉 -11.6%) vs baseline: ~same

Memory: ✅ 71.564MB (SLO: <73.500MB -2.6%) vs baseline: +5.2%


✅ exception-replay-enabled

Time: ✅ 1.367ms (SLO: <1.450ms -5.8%) vs baseline: -0.3%

Memory: ✅ 69.579MB (SLO: <71.500MB -2.7%) vs baseline: +5.2%


✅ iast

Time: ✅ 19.771ms (SLO: <22.250ms 📉 -11.1%) vs baseline: -0.3%

Memory: ✅ 71.329MB (SLO: <75.000MB -4.9%) vs baseline: +5.1%


✅ profiler

Time: ✅ 15.219ms (SLO: <16.550ms -8.0%) vs baseline: +0.6%

Memory: ✅ 60.171MB (SLO: <61.000MB 🟡 -1.4%) vs baseline: +5.5%


✅ resource-renaming

Time: ✅ 19.483ms (SLO: <21.750ms 📉 -10.4%) vs baseline: -0.5%

Memory: ✅ 71.474MB (SLO: <73.500MB -2.8%) vs baseline: +5.2%


✅ span-code-origin

Time: ✅ 19.999ms (SLO: <28.200ms 📉 -29.1%) vs baseline: +1.1%

Memory: ✅ 71.476MB (SLO: <75.000MB -4.7%) vs baseline: +5.4%


✅ tracer

Time: ✅ 19.704ms (SLO: <21.750ms -9.4%) vs baseline: -0.3%

Memory: ✅ 71.456MB (SLO: <75.000MB -4.7%) vs baseline: +5.3%


✅ tracer-and-profiler

Time: ✅ 21.035ms (SLO: <23.500ms 📉 -10.5%) vs baseline: +0.5%

Memory: ✅ 73.220MB (SLO: <75.000MB -2.4%) vs baseline: +4.9%


✅ tracer-dont-create-db-spans

Time: ✅ 19.720ms (SLO: <21.500ms -8.3%) vs baseline: -0.4%

Memory: ✅ 71.376MB (SLO: <75.000MB -4.8%) vs baseline: +5.3%


✅ tracer-minimal

Time: ✅ 17.839ms (SLO: <18.500ms -3.6%) vs baseline: -0.6%

Memory: ✅ 71.388MB (SLO: <75.000MB -4.8%) vs baseline: +5.1%


✅ tracer-no-caches

Time: ✅ 18.865ms (SLO: <19.650ms -4.0%) vs baseline: +0.2%

Memory: ✅ 71.349MB (SLO: <75.000MB -4.9%) vs baseline: +5.2%


✅ tracer-no-databases

Time: ✅ 20.742ms (SLO: <21.100ms 🟡 -1.7%) vs baseline: +0.5%

Memory: ✅ 71.145MB (SLO: <75.000MB -5.1%) vs baseline: +4.9%


✅ tracer-no-middleware

Time: ✅ 19.389ms (SLO: <21.500ms -9.8%) vs baseline: -0.3%

Memory: ✅ 71.133MB (SLO: <75.000MB -5.2%) vs baseline: +4.8%


✅ tracer-no-templates

Time: ✅ 19.474ms (SLO: <22.000ms 📉 -11.5%) vs baseline: -5.8%

Memory: ✅ 71.404MB (SLO: <73.500MB -2.9%) vs baseline: +5.1%


🟡 iastpropagation - 8/8

✅ no-propagation

Time: ✅ 48.750µs (SLO: <60.000µs 📉 -18.8%) vs baseline: +0.2%

Memory: ✅ 41.209MB (SLO: <42.000MB 🟡 -1.9%) vs baseline: +5.3%


✅ propagation_enabled

Time: ✅ 136.025µs (SLO: <190.000µs 📉 -28.4%) vs baseline: +0.3%

Memory: ✅ 41.209MB (SLO: <42.000MB 🟡 -1.9%) vs baseline: +5.4%


✅ propagation_enabled_100

Time: ✅ 1.556ms (SLO: <2.300ms 📉 -32.3%) vs baseline: +0.6%

Memory: ✅ 41.229MB (SLO: <42.000MB 🟡 -1.8%) vs baseline: +5.3%


✅ propagation_enabled_1000

Time: ✅ 29.081ms (SLO: <34.550ms 📉 -15.8%) vs baseline: -0.3%

Memory: ✅ 41.366MB (SLO: <42.000MB 🟡 -1.5%) vs baseline: +5.7%


🟡 otelsdkspan - 24/24

✅ add-event

Time: ✅ 40.363ms (SLO: <42.000ms -3.9%) vs baseline: -0.3%

Memory: ✅ 39.046MB (SLO: <40.750MB -4.2%) vs baseline: +5.9%


✅ add-link

Time: ✅ 36.436ms (SLO: <38.550ms -5.5%) vs baseline: -0.5%

Memory: ✅ 39.007MB (SLO: <40.750MB -4.3%) vs baseline: +6.1%


✅ add-metrics

Time: ✅ 221.044ms (SLO: <232.000ms -4.7%) vs baseline: +0.3%

Memory: ✅ 39.027MB (SLO: <40.750MB -4.2%) vs baseline: +6.1%


✅ add-tags

Time: ✅ 212.082ms (SLO: <221.600ms -4.3%) vs baseline: +0.2%

Memory: ✅ 39.086MB (SLO: <40.750MB -4.1%) vs baseline: +6.1%


✅ get-context

Time: ✅ 29.269ms (SLO: <31.300ms -6.5%) vs baseline: +0.2%

Memory: ✅ 38.987MB (SLO: <40.750MB -4.3%) vs baseline: +6.3%


✅ is-recording

Time: ✅ 29.322ms (SLO: <31.000ms -5.4%) vs baseline: +1.3%

Memory: ✅ 38.987MB (SLO: <40.750MB -4.3%) vs baseline: +5.8%


✅ record-exception

Time: ✅ 63.252ms (SLO: <65.850ms -3.9%) vs baseline: -0.4%

Memory: ✅ 39.046MB (SLO: <40.750MB -4.2%) vs baseline: +5.2%


✅ set-status

Time: ✅ 31.909ms (SLO: <34.150ms -6.6%) vs baseline: -0.1%

Memory: ✅ 38.968MB (SLO: <40.750MB -4.4%) vs baseline: +6.2%


✅ start

Time: ✅ 29.645ms (SLO: <30.150ms 🟡 -1.7%) vs baseline: +3.1%

Memory: ✅ 39.066MB (SLO: <40.750MB -4.1%) vs baseline: +5.9%


✅ start-finish

Time: ✅ 34.093ms (SLO: <35.350ms -3.6%) vs baseline: +0.4%

Memory: ✅ 38.928MB (SLO: <40.750MB -4.5%) vs baseline: +5.6%


✅ start-finish-telemetry

Time: ✅ 34.076ms (SLO: <35.450ms -3.9%) vs baseline: -0.5%

Memory: ✅ 38.987MB (SLO: <40.750MB -4.3%) vs baseline: +5.7%


✅ update-name

Time: ✅ 31.023ms (SLO: <33.400ms -7.1%) vs baseline: -0.3%

Memory: ✅ 39.125MB (SLO: <40.750MB -4.0%) vs baseline: +6.0%


🟡 otelspan - 22/22

✅ add-event

Time: ✅ 40.618ms (SLO: <47.150ms 📉 -13.9%) vs baseline: -1.1%

Memory: ✅ 41.155MB (SLO: <47.000MB 📉 -12.4%) vs baseline: +5.1%


✅ add-metrics

Time: ✅ 236.787ms (SLO: <344.800ms 📉 -31.3%) vs baseline: +0.3%

Memory: ✅ 45.547MB (SLO: <47.500MB -4.1%) vs baseline: +4.9%


✅ add-tags

Time: ✅ 266.280ms (SLO: <330.000ms 📉 -19.3%) vs baseline: +2.0%

Memory: ✅ 45.666MB (SLO: <47.500MB -3.9%) vs baseline: +4.9%


✅ get-context

Time: ✅ 83.335ms (SLO: <92.350ms -9.8%) vs baseline: -0.4%

Memory: ✅ 41.543MB (SLO: <46.500MB 📉 -10.7%) vs baseline: +5.3%


✅ is-recording

Time: ✅ 39.019ms (SLO: <44.500ms 📉 -12.3%) vs baseline: -0.6%

Memory: ✅ 41.126MB (SLO: <47.500MB 📉 -13.4%) vs baseline: +5.6%


✅ record-exception

Time: ✅ 61.142ms (SLO: <67.650ms -9.6%) vs baseline: -0.6%

Memory: ✅ 41.826MB (SLO: <47.000MB 📉 -11.0%) vs baseline: +5.5%


✅ set-status

Time: ✅ 44.945ms (SLO: <50.400ms 📉 -10.8%) vs baseline: ~same

Memory: ✅ 41.173MB (SLO: <47.000MB 📉 -12.4%) vs baseline: +5.3%


✅ start

Time: ✅ 40.015ms (SLO: <44.500ms 📉 -10.1%) vs baseline: +3.1%

Memory: ✅ 41.112MB (SLO: <47.000MB 📉 -12.5%) vs baseline: +5.5%


✅ start-finish

Time: ✅ 90.100ms (SLO: <92.000ms -2.1%) vs baseline: +0.1%

Memory: ✅ 38.732MB (SLO: <46.500MB 📉 -16.7%) vs baseline: +5.3%


✅ start-finish-telemetry

Time: ✅ 91.686ms (SLO: <93.000ms 🟡 -1.4%) vs baseline: ~same

Memory: ✅ 38.850MB (SLO: <46.500MB 📉 -16.5%) vs baseline: +5.5%


✅ update-name

Time: ✅ 40.160ms (SLO: <45.150ms 📉 -11.1%) vs baseline: -0.7%

Memory: ✅ 41.194MB (SLO: <47.000MB 📉 -12.4%) vs baseline: +5.2%


🟡 recursivecomputation - 8/8

✅ deep

Time: ✅ 311.691ms (SLO: <320.950ms -2.9%) vs baseline: -0.2%

Memory: ✅ 37.356MB (SLO: <38.750MB -3.6%) vs baseline: +5.1%


✅ deep-profiled

Time: ✅ 329.197ms (SLO: <359.150ms -8.3%) vs baseline: +0.2%

Memory: ✅ 43.765MB (SLO: <46.000MB -4.9%) vs baseline: +5.3%


✅ medium

Time: ✅ 7.351ms (SLO: <7.450ms 🟡 -1.3%) vs baseline: -0.5%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.5%


✅ shallow

Time: ✅ 1.039ms (SLO: <1.050ms 🟡 -1.1%) vs baseline: +1.4%

Memory: ✅ 36.176MB (SLO: <38.000MB -4.8%) vs baseline: +5.4%


🟡 span - 25/25

✅ add-event

Time: ✅ 19.546ms (SLO: <22.500ms 📉 -13.1%) vs baseline: -1.8%

Memory: ✅ 38.418MB (SLO: <53.000MB 📉 -27.5%) vs baseline: +5.4%


✅ add-metrics

Time: ✅ 89.183ms (SLO: <93.500ms -4.6%) vs baseline: -0.6%

Memory: ✅ 42.959MB (SLO: <53.000MB 📉 -18.9%) vs baseline: +5.5%


✅ add-tags

Time: ✅ 137.241ms (SLO: <155.000ms 📉 -11.5%) vs baseline: ~same

Memory: ✅ 42.925MB (SLO: <53.000MB 📉 -19.0%) vs baseline: +5.2%


✅ get-context

Time: ✅ 18.722ms (SLO: <20.500ms -8.7%) vs baseline: -1.9%

Memory: ✅ 38.429MB (SLO: <53.000MB 📉 -27.5%) vs baseline: +6.2%


✅ is-recording

Time: ✅ 18.931ms (SLO: <20.500ms -7.7%) vs baseline: -1.2%

Memory: ✅ 38.284MB (SLO: <53.000MB 📉 -27.8%) vs baseline: +5.5%


✅ record-exception

Time: ✅ 38.674ms (SLO: <41.000ms -5.7%) vs baseline: ~same

Memory: ✅ 38.818MB (SLO: <53.000MB 📉 -26.8%) vs baseline: +5.6%


✅ set-status

Time: ✅ 20.403ms (SLO: <22.000ms -7.3%) vs baseline: -1.6%

Memory: ✅ 38.353MB (SLO: <53.000MB 📉 -27.6%) vs baseline: +5.4%


✅ start

Time: ✅ 19.726ms (SLO: <20.500ms -3.8%) vs baseline: +3.5%

Memory: ✅ 38.307MB (SLO: <53.000MB 📉 -27.7%) vs baseline: +5.3%


✅ start-finish

Time: ✅ 58.092ms (SLO: <58.500ms 🟡 -0.7%) vs baseline: -0.1%

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.4%


✅ start-finish-telemetry

Time: ✅ 59.298ms (SLO: <60.000ms 🟡 -1.2%) vs baseline: -0.7%


✅ start-finish-traceid128

Time: ✅ 60.584ms (SLO: <62.000ms -2.3%) vs baseline: -0.8%

Memory: ✅ 36.196MB (SLO: <38.000MB -4.7%) vs baseline: +5.3%


✅ start-traceid128

Time: ✅ 18.654ms (SLO: <22.500ms 📉 -17.1%) vs baseline: -2.6%

Memory: ✅ 38.454MB (SLO: <53.000MB 📉 -27.4%) vs baseline: +6.0%


✅ update-name

Time: ✅ 19.276ms (SLO: <22.000ms 📉 -12.4%) vs baseline: -1.7%

Memory: ✅ 38.376MB (SLO: <53.000MB 📉 -27.6%) vs baseline: +5.3%


🟡 tracer - 6/6

✅ large

Time: ✅ 33.104ms (SLO: <33.950ms -2.5%) vs baseline: -0.6%

Memory: ✅ 37.808MB (SLO: <39.250MB -3.7%) vs baseline: +6.1%


✅ medium

Time: ✅ 3.329ms (SLO: <3.500ms -4.9%) vs baseline: -0.3%

Memory: ✅ 36.255MB (SLO: <38.750MB -6.4%) vs baseline: +5.3%


✅ small

Time: ✅ 387.359µs (SLO: <390.000µs 🟡 -0.7%) vs baseline: +3.4%

Memory: ✅ 36.196MB (SLO: <38.750MB -6.6%) vs baseline: +5.0%

⚠️ Unstable Tests (2 suites)
⚠️ coreapiscenario - 10/10 (1 unstable)

⚠️ context_with_data_listeners

Time: ⚠️ 13.604µs (SLO: <20.000µs 📉 -32.0%) vs baseline: ~same

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.3%


✅ context_with_data_no_listeners

Time: ✅ 3.600µs (SLO: <10.000µs 📉 -64.0%) vs baseline: +0.3%

Memory: ✅ 36.196MB (SLO: <38.000MB -4.7%) vs baseline: +5.1%


✅ get_item_exists

Time: ✅ 0.580µs (SLO: <10.000µs 📉 -94.2%) vs baseline: -1.0%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.4%


✅ get_item_missing

Time: ✅ 0.640µs (SLO: <10.000µs 📉 -93.6%) vs baseline: ~same

Memory: ✅ 36.313MB (SLO: <38.000MB -4.4%) vs baseline: +5.4%


✅ set_item

Time: ✅ 24.552µs (SLO: <30.000µs 📉 -18.2%) vs baseline: +1.3%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.1%


⚠️ packagesupdateimporteddependencies - 24/24 (1 unstable)

✅ import_many

Time: ✅ 156.458µs (SLO: <170.000µs -8.0%) vs baseline: +0.1%

Memory: ✅ 40.928MB (SLO: <46.000MB 📉 -11.0%) vs baseline: +5.2%


✅ import_many_cached

Time: ✅ 122.240µs (SLO: <130.000µs -6.0%) vs baseline: ~same

Memory: ✅ 40.965MB (SLO: <46.000MB 📉 -10.9%) vs baseline: +5.2%


✅ import_many_stdlib

Time: ✅ 1.248ms (SLO: <1.750ms 📉 -28.7%) vs baseline: -0.3%

Memory: ✅ 41.052MB (SLO: <46.000MB 📉 -10.8%) vs baseline: +5.3%


⚠️ import_many_stdlib_cached

Time: ⚠️ 0.621ms (SLO: <1.100ms 📉 -43.5%) vs baseline: +0.3%

Memory: ✅ 41.088MB (SLO: <46.000MB 📉 -10.7%) vs baseline: +4.9%


✅ import_many_unknown

Time: ✅ 835.151µs (SLO: <890.000µs -6.2%) vs baseline: +0.6%

Memory: ✅ 41.191MB (SLO: <46.000MB 📉 -10.5%) vs baseline: +5.3%


✅ import_many_unknown_cached

Time: ✅ 798.221µs (SLO: <870.000µs -8.3%) vs baseline: +0.6%

Memory: ✅ 41.307MB (SLO: <46.000MB 📉 -10.2%) vs baseline: +5.6%


✅ import_one

Time: ✅ 21.201µs (SLO: <30.000µs 📉 -29.3%) vs baseline: +0.9%

Memory: ✅ 40.824MB (SLO: <46.000MB 📉 -11.3%) vs baseline: +5.1%


✅ import_one_cache

Time: ✅ 7.330µs (SLO: <10.000µs 📉 -26.7%) vs baseline: -0.2%

Memory: ✅ 40.992MB (SLO: <46.000MB 📉 -10.9%) vs baseline: +5.1%


✅ import_one_stdlib

Time: ✅ 20.081µs (SLO: <30.000µs 📉 -33.1%) vs baseline: +1.2%

Memory: ✅ 40.890MB (SLO: <46.000MB 📉 -11.1%) vs baseline: +5.0%


✅ import_one_stdlib_cache

Time: ✅ 7.273µs (SLO: <10.000µs 📉 -27.3%) vs baseline: -1.1%

Memory: ✅ 41.066MB (SLO: <46.000MB 📉 -10.7%) vs baseline: +5.7%


✅ import_one_unknown

Time: ✅ 47.083µs (SLO: <50.000µs -5.8%) vs baseline: +0.5%

Memory: ✅ 41.146MB (SLO: <46.000MB 📉 -10.6%) vs baseline: +5.6%


✅ import_one_unknown_cache

Time: ✅ 7.286µs (SLO: <10.000µs 📉 -27.1%) vs baseline: -0.6%

Memory: ✅ 41.068MB (SLO: <43.000MB -4.5%) vs baseline: +5.7%

✅ All Tests Passing (14 suites)
codeprovenancefork - 2/2

✅ fork-10

Time: ✅ 2.197s (SLO: <2.400s -8.5%) vs baseline: +2.9%

Memory: ✅ 17.360MB (SLO: <20.000MB 📉 -13.2%) vs baseline: +4.7%


errortrackingdjangosimple - 6/6

✅ errortracking-enabled-all

Time: ✅ 17.620ms (SLO: <19.850ms 📉 -11.2%) vs baseline: +0.1%

Memory: ✅ 70.923MB (SLO: <75.000MB -5.4%) vs baseline: +5.2%


✅ errortracking-enabled-user

Time: ✅ 17.563ms (SLO: <19.400ms -9.5%) vs baseline: ~same

Memory: ✅ 70.980MB (SLO: <75.000MB -5.4%) vs baseline: +5.2%


✅ tracer-enabled

Time: ✅ 17.459ms (SLO: <19.450ms 📉 -10.2%) vs baseline: -0.1%

Memory: ✅ 70.948MB (SLO: <75.000MB -5.4%) vs baseline: +5.3%


errortrackingflasksqli - 6/6

✅ errortracking-enabled-all

Time: ✅ 2.123ms (SLO: <2.300ms -7.7%) vs baseline: +0.6%

Memory: ✅ 58.353MB (SLO: <60.000MB -2.7%) vs baseline: +5.1%


✅ errortracking-enabled-user

Time: ✅ 2.127ms (SLO: <2.250ms -5.4%) vs baseline: +0.3%

Memory: ✅ 58.393MB (SLO: <60.000MB -2.7%) vs baseline: +5.1%


✅ tracer-enabled

Time: ✅ 2.119ms (SLO: <2.300ms -7.9%) vs baseline: +0.2%

Memory: ✅ 58.432MB (SLO: <60.000MB -2.6%) vs baseline: +5.2%


flasksimple - 16/16

✅ appsec-get

Time: ✅ 3.391ms (SLO: <4.750ms 📉 -28.6%) vs baseline: -0.6%

Memory: ✅ 58.593MB (SLO: <66.500MB 📉 -11.9%) vs baseline: +5.4%


✅ appsec-post

Time: ✅ 2.897ms (SLO: <6.750ms 📉 -57.1%) vs baseline: ~same

Memory: ✅ 58.592MB (SLO: <66.500MB 📉 -11.9%) vs baseline: +5.5%


✅ appsec-telemetry

Time: ✅ 3.413ms (SLO: <4.750ms 📉 -28.1%) vs baseline: +0.5%

Memory: ✅ 58.576MB (SLO: <66.500MB 📉 -11.9%) vs baseline: +5.5%


✅ debugger

Time: ✅ 1.883ms (SLO: <2.000ms -5.8%) vs baseline: ~same

Memory: ✅ 49.322MB (SLO: <51.500MB -4.2%) vs baseline: +5.5%


✅ iast-get

Time: ✅ 1.866ms (SLO: <2.000ms -6.7%) vs baseline: ~same

Memory: ✅ 46.105MB (SLO: <49.000MB -5.9%) vs baseline: +5.8%


✅ profiler

Time: ✅ 1.916ms (SLO: <2.100ms -8.8%) vs baseline: +0.3%

Memory: ✅ 52.002MB (SLO: <53.500MB -2.8%) vs baseline: +5.4%


✅ resource-renaming

Time: ✅ 3.386ms (SLO: <3.650ms -7.2%) vs baseline: ~same

Memory: ✅ 58.597MB (SLO: <60.000MB -2.3%) vs baseline: +5.6%


✅ tracer

Time: ✅ 3.392ms (SLO: <3.650ms -7.1%) vs baseline: ~same

Memory: ✅ 58.492MB (SLO: <60.000MB -2.5%) vs baseline: +5.4%


flasksqli - 6/6

✅ appsec-enabled

Time: ✅ 2.114ms (SLO: <4.200ms 📉 -49.7%) vs baseline: +0.3%

Memory: ✅ 58.432MB (SLO: <66.000MB 📉 -11.5%) vs baseline: +5.2%


✅ iast-enabled

Time: ✅ 2.120ms (SLO: <2.800ms 📉 -24.3%) vs baseline: +0.3%

Memory: ✅ 58.511MB (SLO: <62.500MB -6.4%) vs baseline: +5.3%


✅ tracer-enabled

Time: ✅ 2.114ms (SLO: <2.250ms -6.0%) vs baseline: ~same

Memory: ✅ 58.471MB (SLO: <60.000MB -2.5%) vs baseline: +5.2%


httppropagationextract - 60/60

✅ all_styles_all_headers

Time: ✅ 81.145µs (SLO: <100.000µs 📉 -18.9%) vs baseline: +6.6%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.3%


✅ b3_headers

Time: ✅ 12.856µs (SLO: <20.000µs 📉 -35.7%) vs baseline: ~same

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.2%


✅ b3_single_headers

Time: ✅ 12.017µs (SLO: <20.000µs 📉 -39.9%) vs baseline: +1.1%

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.0%


✅ datadog_tracecontext_tracestate_not_propagated_on_trace_id_no_match

Time: ✅ 60.568µs (SLO: <80.000µs 📉 -24.3%) vs baseline: +0.6%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.6%


✅ datadog_tracecontext_tracestate_propagated_on_trace_id_match

Time: ✅ 64.137µs (SLO: <80.000µs 📉 -19.8%) vs baseline: +1.3%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.5%


✅ empty_headers

Time: ✅ 1.305µs (SLO: <10.000µs 📉 -86.9%) vs baseline: +0.2%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ full_t_id_datadog_headers

Time: ✅ 21.550µs (SLO: <30.000µs 📉 -28.2%) vs baseline: ~same

Memory: ✅ 36.471MB (SLO: <38.000MB -4.0%) vs baseline: +6.0%


✅ invalid_priority_header

Time: ✅ 5.964µs (SLO: <10.000µs 📉 -40.4%) vs baseline: +1.0%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ invalid_span_id_header

Time: ✅ 5.938µs (SLO: <10.000µs 📉 -40.6%) vs baseline: +0.8%

Memory: ✅ 36.372MB (SLO: <38.000MB -4.3%) vs baseline: +5.4%


✅ invalid_tags_header

Time: ✅ 5.932µs (SLO: <10.000µs 📉 -40.7%) vs baseline: -0.5%

Memory: ✅ 36.451MB (SLO: <38.000MB -4.1%) vs baseline: +5.7%


✅ invalid_trace_id_header

Time: ✅ 5.961µs (SLO: <10.000µs 📉 -40.4%) vs baseline: +0.2%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.3%


✅ large_header_no_matches

Time: ✅ 27.052µs (SLO: <30.000µs -9.8%) vs baseline: +0.3%

Memory: ✅ 36.333MB (SLO: <38.000MB -4.4%) vs baseline: +5.1%


✅ large_valid_headers_all

Time: ✅ 28.457µs (SLO: <40.000µs 📉 -28.9%) vs baseline: +1.8%

Memory: ✅ 36.313MB (SLO: <38.000MB -4.4%) vs baseline: +5.6%


✅ medium_header_no_matches

Time: ✅ 9.262µs (SLO: <20.000µs 📉 -53.7%) vs baseline: +0.4%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.1%


✅ medium_valid_headers_all

Time: ✅ 10.741µs (SLO: <20.000µs 📉 -46.3%) vs baseline: +0.4%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ none_propagation_style

Time: ✅ 1.410µs (SLO: <10.000µs 📉 -85.9%) vs baseline: +0.9%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.2%


✅ tracecontext_headers

Time: ✅ 33.019µs (SLO: <40.000µs 📉 -17.5%) vs baseline: +0.9%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.0%


✅ valid_headers_all

Time: ✅ 6.002µs (SLO: <10.000µs 📉 -40.0%) vs baseline: +1.7%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.2%


✅ valid_headers_basic

Time: ✅ 5.572µs (SLO: <10.000µs 📉 -44.3%) vs baseline: +1.1%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.5%


✅ wsgi_empty_headers

Time: ✅ 1.310µs (SLO: <10.000µs 📉 -86.9%) vs baseline: +0.8%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.2%


✅ wsgi_invalid_priority_header

Time: ✅ 5.972µs (SLO: <10.000µs 📉 -40.3%) vs baseline: -0.4%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ wsgi_invalid_span_id_header

Time: ✅ 1.299µs (SLO: <10.000µs 📉 -87.0%) vs baseline: -0.8%

Memory: ✅ 36.294MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ wsgi_invalid_tags_header

Time: ✅ 5.970µs (SLO: <10.000µs 📉 -40.3%) vs baseline: -0.8%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.3%


✅ wsgi_invalid_trace_id_header

Time: ✅ 5.965µs (SLO: <10.000µs 📉 -40.4%) vs baseline: -1.1%

Memory: ✅ 36.451MB (SLO: <38.000MB -4.1%) vs baseline: +5.8%


✅ wsgi_large_header_no_matches

Time: ✅ 28.255µs (SLO: <40.000µs 📉 -29.4%) vs baseline: +0.3%

Memory: ✅ 36.313MB (SLO: <38.000MB -4.4%) vs baseline: +5.5%


✅ wsgi_large_valid_headers_all

Time: ✅ 29.234µs (SLO: <40.000µs 📉 -26.9%) vs baseline: ~same

Memory: ✅ 36.392MB (SLO: <38.000MB -4.2%) vs baseline: +5.6%


✅ wsgi_medium_header_no_matches

Time: ✅ 9.496µs (SLO: <20.000µs 📉 -52.5%) vs baseline: -0.1%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.2%


✅ wsgi_medium_valid_headers_all

Time: ✅ 11.125µs (SLO: <20.000µs 📉 -44.4%) vs baseline: +1.7%

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.0%


✅ wsgi_valid_headers_all

Time: ✅ 6.029µs (SLO: <10.000µs 📉 -39.7%) vs baseline: +1.1%

Memory: ✅ 36.392MB (SLO: <38.000MB -4.2%) vs baseline: +5.5%


✅ wsgi_valid_headers_basic

Time: ✅ 5.553µs (SLO: <10.000µs 📉 -44.5%) vs baseline: ~same

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.3%


httppropagationinject - 16/16

✅ ids_only

Time: ✅ 20.828µs (SLO: <30.000µs 📉 -30.6%) vs baseline: +4.3%

Memory: ✅ 36.372MB (SLO: <38.000MB -4.3%) vs baseline: +5.4%


✅ with_all

Time: ✅ 26.996µs (SLO: <40.000µs 📉 -32.5%) vs baseline: +0.2%

Memory: ✅ 36.353MB (SLO: <38.000MB -4.3%) vs baseline: +5.4%


✅ with_dd_origin

Time: ✅ 23.789µs (SLO: <30.000µs 📉 -20.7%) vs baseline: -0.7%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.2%


✅ with_priority_and_origin

Time: ✅ 23.293µs (SLO: <40.000µs 📉 -41.8%) vs baseline: -0.6%

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.2%


✅ with_sampling_priority

Time: ✅ 20.127µs (SLO: <30.000µs 📉 -32.9%) vs baseline: +0.5%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.4%


✅ with_tags

Time: ✅ 25.150µs (SLO: <40.000µs 📉 -37.1%) vs baseline: ~same

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.3%


✅ with_tags_invalid

Time: ✅ 26.523µs (SLO: <40.000µs 📉 -33.7%) vs baseline: +0.2%

Memory: ✅ 36.313MB (SLO: <38.000MB -4.4%) vs baseline: +5.4%


✅ with_tags_max_size

Time: ✅ 25.593µs (SLO: <40.000µs 📉 -36.0%) vs baseline: ~same

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +4.9%


iastaspectssplit - 12/12

✅ rsplit_aspect

Time: ✅ 163.782µs (SLO: <250.000µs 📉 -34.5%) vs baseline: +4.5%

Memory: ✅ 43.831MB (SLO: <46.000MB -4.7%) vs baseline: +5.0%


✅ rsplit_noaspect

Time: ✅ 160.567µs (SLO: <250.000µs 📉 -35.8%) vs baseline: -0.5%

Memory: ✅ 43.836MB (SLO: <46.000MB -4.7%) vs baseline: +5.8%


✅ split_aspect

Time: ✅ 151.717µs (SLO: <250.000µs 📉 -39.3%) vs baseline: -0.5%

Memory: ✅ 43.880MB (SLO: <46.000MB -4.6%) vs baseline: +5.7%


✅ split_noaspect

Time: ✅ 157.661µs (SLO: <250.000µs 📉 -36.9%) vs baseline: +0.9%

Memory: ✅ 43.791MB (SLO: <46.000MB -4.8%) vs baseline: +5.8%


✅ splitlines_aspect

Time: ✅ 147.377µs (SLO: <250.000µs 📉 -41.0%) vs baseline: -0.1%

Memory: ✅ 43.841MB (SLO: <46.000MB -4.7%) vs baseline: +5.6%


✅ splitlines_noaspect

Time: ✅ 153.307µs (SLO: <250.000µs 📉 -38.7%) vs baseline: -2.0%

Memory: ✅ 43.833MB (SLO: <46.000MB -4.7%) vs baseline: +5.5%


packagespackageforrootmodulemapping - 4/4

✅ cache_off

Time: ✅ 345.591ms (SLO: <354.300ms -2.5%) vs baseline: -0.1%

Memory: ✅ 42.706MB (SLO: <46.000MB -7.2%) vs baseline: +5.2%


✅ cache_on

Time: ✅ 0.380µs (SLO: <10.000µs 📉 -96.2%) vs baseline: -0.6%

Memory: ✅ 41.592MB (SLO: <46.000MB -9.6%) vs baseline: +5.2%


rand - 2/2

✅ rand128bits

Time: ✅ 0.181µs (SLO: <21.000µs 📉 -99.1%) vs baseline: -2.0%


✅ rand64bits

Time: ✅ 0.123µs (SLO: <15.000µs 📉 -99.2%) vs baseline: +5.3%


ratelimiter - 12/12

✅ defaults

Time: ✅ 2.365µs (SLO: <10.000µs 📉 -76.3%) vs baseline: +0.6%

Memory: ✅ 36.569MB (SLO: <38.000MB -3.8%) vs baseline: +6.3%


✅ high_rate_limit

Time: ✅ 2.412µs (SLO: <10.000µs 📉 -75.9%) vs baseline: ~same

Memory: ✅ 36.530MB (SLO: <38.000MB -3.9%) vs baseline: +5.1%


✅ long_window

Time: ✅ 2.363µs (SLO: <10.000µs 📉 -76.4%) vs baseline: +0.5%

Memory: ✅ 36.549MB (SLO: <38.000MB -3.8%) vs baseline: +5.8%


✅ low_rate_limit

Time: ✅ 2.368µs (SLO: <10.000µs 📉 -76.3%) vs baseline: -0.7%

Memory: ✅ 36.530MB (SLO: <38.000MB -3.9%) vs baseline: +5.1%


✅ no_rate_limit

Time: ✅ 0.833µs (SLO: <10.000µs 📉 -91.7%) vs baseline: +1.0%

Memory: ✅ 36.549MB (SLO: <38.000MB -3.8%) vs baseline: +6.1%


✅ short_window

Time: ✅ 2.491µs (SLO: <10.000µs 📉 -75.1%) vs baseline: ~same

Memory: ✅ 36.569MB (SLO: <38.000MB -3.8%) vs baseline: +6.5%


samplingrules - 8/8

✅ average_match

Time: ✅ 148.067µs (SLO: <200.000µs 📉 -26.0%) vs baseline: ~same

Memory: ✅ 36.196MB (SLO: <38.000MB -4.7%) vs baseline: +5.4%


✅ high_match

Time: ✅ 170.041µs (SLO: <200.000µs 📉 -15.0%) vs baseline: +0.4%

Memory: ✅ 36.156MB (SLO: <38.000MB -4.9%) vs baseline: +5.1%


✅ low_match

Time: ✅ 121.640µs (SLO: <130.000µs -6.4%) vs baseline: -1.1%

Memory: ✅ 701.475MB (SLO: <780.000MB 📉 -10.1%) vs baseline: +4.9%


✅ very_low_match

Time: ✅ 2.678ms (SLO: <4.000ms 📉 -33.1%) vs baseline: -0.3%

Memory: ✅ 78.924MB (SLO: <85.000MB -7.1%) vs baseline: +5.3%


sethttpmeta - 32/32

✅ all-disabled

Time: ✅ 10.589µs (SLO: <20.000µs 📉 -47.1%) vs baseline: ~same

Memory: ✅ 37.277MB (SLO: <38.750MB -3.8%) vs baseline: +5.9%


✅ all-enabled

Time: ✅ 39.703µs (SLO: <50.000µs 📉 -20.6%) vs baseline: +1.8%

Memory: ✅ 37.179MB (SLO: <38.750MB -4.1%) vs baseline: +5.6%


✅ collectipvariant_exists

Time: ✅ 39.816µs (SLO: <50.000µs 📉 -20.4%) vs baseline: ~same

Memory: ✅ 37.100MB (SLO: <38.750MB -4.3%) vs baseline: +5.2%


✅ no-collectipvariant

Time: ✅ 39.099µs (SLO: <50.000µs 📉 -21.8%) vs baseline: +0.6%

Memory: ✅ 37.179MB (SLO: <38.750MB -4.1%) vs baseline: +5.8%


✅ no-useragentvariant

Time: ✅ 37.708µs (SLO: <50.000µs 📉 -24.6%) vs baseline: -0.5%

Memory: ✅ 37.080MB (SLO: <38.750MB -4.3%) vs baseline: +5.2%


✅ obfuscation-no-query

Time: ✅ 39.469µs (SLO: <50.000µs 📉 -21.1%) vs baseline: -1.1%

Memory: ✅ 37.238MB (SLO: <38.750MB -3.9%) vs baseline: +5.5%


✅ obfuscation-regular-case-explicit-query

Time: ✅ 75.847µs (SLO: <90.000µs 📉 -15.7%) vs baseline: ~same

Memory: ✅ 37.454MB (SLO: <38.750MB -3.3%) vs baseline: +5.6%


✅ obfuscation-regular-case-implicit-query

Time: ✅ 76.368µs (SLO: <90.000µs 📉 -15.1%) vs baseline: -0.2%

Memory: ✅ 37.493MB (SLO: <38.750MB -3.2%) vs baseline: +5.0%


✅ obfuscation-send-querystring-disabled

Time: ✅ 154.694µs (SLO: <170.000µs -9.0%) vs baseline: -0.1%

Memory: ✅ 37.415MB (SLO: <38.750MB -3.4%) vs baseline: +5.1%


✅ obfuscation-worst-case-explicit-query

Time: ✅ 148.762µs (SLO: <160.000µs -7.0%) vs baseline: -0.1%

Memory: ✅ 37.532MB (SLO: <38.750MB -3.1%) vs baseline: +5.6%


✅ obfuscation-worst-case-implicit-query

Time: ✅ 155.368µs (SLO: <170.000µs -8.6%) vs baseline: +0.2%

Memory: ✅ 37.454MB (SLO: <38.750MB -3.3%) vs baseline: +5.2%


✅ useragentvariant_exists_1

Time: ✅ 38.598µs (SLO: <50.000µs 📉 -22.8%) vs baseline: +0.4%

Memory: ✅ 37.218MB (SLO: <38.750MB -4.0%) vs baseline: +5.5%


✅ useragentvariant_exists_2

Time: ✅ 39.588µs (SLO: <50.000µs 📉 -20.8%) vs baseline: +0.2%

Memory: ✅ 37.139MB (SLO: <38.750MB -4.2%) vs baseline: +5.5%


✅ useragentvariant_exists_3

Time: ✅ 39.099µs (SLO: <50.000µs 📉 -21.8%) vs baseline: -0.2%

Memory: ✅ 37.257MB (SLO: <38.750MB -3.9%) vs baseline: +5.8%


✅ useragentvariant_not_exists_1

Time: ✅ 38.634µs (SLO: <50.000µs 📉 -22.7%) vs baseline: +0.2%

Memory: ✅ 37.080MB (SLO: <38.750MB -4.3%) vs baseline: +5.2%


✅ useragentvariant_not_exists_2

Time: ✅ 38.382µs (SLO: <50.000µs 📉 -23.2%) vs baseline: -0.3%

Memory: ✅ 37.198MB (SLO: <38.750MB -4.0%) vs baseline: +5.6%


telemetryaddmetric - 30/30

✅ 1-count-metric-1-times

Time: ✅ 2.285µs (SLO: <20.000µs 📉 -88.6%) vs baseline: +8.8%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.4%


✅ 1-count-metrics-100-times

Time: ✅ 154.692µs (SLO: <220.000µs 📉 -29.7%) vs baseline: +1.2%

Memory: ✅ 36.176MB (SLO: <38.000MB -4.8%) vs baseline: +5.2%


✅ 1-distribution-metric-1-times

Time: ✅ 2.378µs (SLO: <20.000µs 📉 -88.1%) vs baseline: -3.7%

Memory: ✅ 36.196MB (SLO: <38.000MB -4.7%) vs baseline: +4.9%


✅ 1-distribution-metrics-100-times

Time: ✅ 164.664µs (SLO: <230.000µs 📉 -28.4%) vs baseline: ~same

Memory: ✅ 36.196MB (SLO: <38.000MB -4.7%) vs baseline: +5.3%


✅ 1-gauge-metric-1-times

Time: ✅ 1.982µs (SLO: <20.000µs 📉 -90.1%) vs baseline: -0.5%

Memory: ✅ 36.274MB (SLO: <38.000MB -4.5%) vs baseline: +5.3%


✅ 1-gauge-metrics-100-times

Time: ✅ 136.701µs (SLO: <150.000µs -8.9%) vs baseline: +0.1%

Memory: ✅ 36.235MB (SLO: <38.000MB -4.6%) vs baseline: +5.1%


✅ 1-rate-metric-1-times

Time: ✅ 2.280µs (SLO: <20.000µs 📉 -88.6%) vs baseline: +1.2%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.7%


✅ 1-rate-metrics-100-times

Time: ✅ 170.579µs (SLO: <250.000µs 📉 -31.8%) vs baseline: +2.7%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.1%


✅ 100-count-metrics-100-times

Time: ✅ 15.413ms (SLO: <22.000ms 📉 -29.9%) vs baseline: +1.5%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.4%


✅ 100-distribution-metrics-100-times

Time: ✅ 1.722ms (SLO: <2.550ms 📉 -32.5%) vs baseline: -1.8%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.4%


✅ 100-gauge-metrics-100-times

Time: ✅ 1.405ms (SLO: <1.550ms -9.4%) vs baseline: +0.7%

Memory: ✅ 36.255MB (SLO: <38.000MB -4.6%) vs baseline: +5.5%


✅ 100-rate-metrics-100-times

Time: ✅ 1.749ms (SLO: <2.550ms 📉 -31.4%) vs baseline: +1.9%

Memory: ✅ 36.215MB (SLO: <38.000MB -4.7%) vs baseline: +5.3%


✅ flush-1-metric

Time: ✅ 3.628µs (SLO: <20.000µs 📉 -81.9%) vs baseline: +2.3%

Memory: ✅ 36.510MB (SLO: <38.000MB -3.9%) vs baseline: +6.0%


✅ flush-100-metrics

Time: ✅ 174.165µs (SLO: <250.000µs 📉 -30.3%) vs baseline: -0.6%

Memory: ✅ 36.608MB (SLO: <38.000MB -3.7%) vs baseline: +6.1%


✅ flush-1000-metrics

Time: ✅ 2.214ms (SLO: <2.500ms 📉 -11.4%) vs baseline: ~same

Memory: ✅ 37.454MB (SLO: <38.750MB -3.3%) vs baseline: +5.4%

ℹ️ Scenarios Missing SLO Configuration (48 scenarios)

The following scenarios exist in candidate data but have no SLO thresholds configured:

  • coreapiscenario-core_dispatch_listeners
  • coreapiscenario-core_dispatch_no_listeners
  • coreapiscenario-core_dispatch_with_results_listeners
  • coreapiscenario-core_dispatch_with_results_no_listeners
  • djangosimple-baseline
  • errortrackingdjangosimple-baseline
  • errortrackingflasksqli-baseline
  • flasksimple-baseline
  • flasksqli-baseline
  • iast_aspects-re_expand_aspect
  • iast_aspects-re_expand_noaspect
  • iast_aspects-re_findall_aspect
  • iast_aspects-re_findall_noaspect
  • iast_aspects-re_finditer_aspect
  • iast_aspects-re_finditer_noaspect
  • iast_aspects-re_fullmatch_aspect
  • iast_aspects-re_fullmatch_noaspect
  • iast_aspects-re_group_aspect
  • iast_aspects-re_group_noaspect
  • iast_aspects-re_groups_aspect
  • iast_aspects-re_groups_noaspect
  • iast_aspects-re_match_aspect
  • iast_aspects-re_match_noaspect
  • iast_aspects-re_search_aspect
  • iast_aspects-re_search_noaspect
  • iast_aspects-re_sub_aspect
  • iast_aspects-re_sub_noaspect
  • iast_aspects-re_subn_aspect
  • iast_aspects-re_subn_noaspect
  • sethttpmeta-obfuscation-disabled
  • startup-baseline
  • startup-baseline_django
  • startup-baseline_flask
  • startup-ddtrace_run
  • startup-ddtrace_run_appsec
  • startup-ddtrace_run_profiling
  • startup-ddtrace_run_runtime_metrics
  • startup-ddtrace_run_send_span
  • startup-ddtrace_run_telemetry_disabled
  • startup-ddtrace_run_telemetry_enabled
  • startup-import_ddtrace
  • startup-import_ddtrace_auto
  • startup-import_ddtrace_auto_django
  • startup-import_ddtrace_auto_flask
  • startup-import_ddtrace_django
  • startup-import_ddtrace_flask
  • telemetrydependencies-first-50-deps-sca-off
  • telemetrydependencies-first-50-deps-sca-on

@avara1986 avara1986 added the changelog/no-changelog A changelog entry is not required for this PR. label Mar 27, 2026
@avara1986 avara1986 changed the title runtime SCA feat(sca): runtime SCA reachability Mar 27, 2026
@datadog-prod-us1-3
Copy link
Copy Markdown

datadog-prod-us1-3 Bot commented Mar 27, 2026

Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: f4dd6de | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

avara1986 added a commit that referenced this pull request Apr 6, 2026
Move the native _stacktrace C extension from ddtrace/appsec/_iast/ to
ddtrace/appsec/_shared/ so it can be reused by both IAST and SCA
without creating a dependency from SCA into IAST internals.

Split out from #17156 to keep PRs incremental and reviewable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
avara1986 added a commit that referenced this pull request Apr 6, 2026
…h_utils

Move rel_path() and the frame-walking logic (_compute_file_line) from
VulnerabilityBase in _iast/taint_sinks/_base.py to shared functions in
_patch_utils.py so both IAST and SCA can reuse them without depending
on IAST internals.

Split out from #17156 to keep PRs incremental and reviewable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
avara1986 added a commit that referenced this pull request Apr 6, 2026
…h_utils

Move rel_path() and the frame-walking logic (_compute_file_line) from
VulnerabilityBase in _iast/taint_sinks/_base.py to shared functions in
_patch_utils.py so both IAST and SCA can reuse them without depending
on IAST internals.

Split out from #17156 to keep PRs incremental and reviewable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
avara1986 added a commit that referenced this pull request Apr 6, 2026
…h_utils

Move rel_path() and the frame-walking logic (_compute_file_line) from
VulnerabilityBase in _iast/taint_sinks/_base.py to shared functions in
_patch_utils.py so both IAST and SCA can reuse them without depending
on IAST internals.

Also migrates insecure_cookie.py and updates test_weak_hash.py mock
target accordingly.

Split out from #17156 to keep PRs incremental and reviewable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 7, 2026
…h_utils (#17334)

## Summary
- Extract `rel_path()` and `_compute_file_line()` from `VulnerabilityBase` in `_iast/taint_sinks/_base.py` into shared functions (`rel_path` and `get_caller_frame_info`) in `_patch_utils.py`.
- Migrate `insecure_cookie.py` to use the shared `get_caller_frame_info()` instead of `cls._compute_file_line()`.
- Update `test_weak_hash.py` mock target from `get_info_frame` to `get_caller_frame_info`.
- Both IAST and SCA can now reuse these functions without depending on IAST internals.

Split out from #17156 to keep PRs incremental and reviewable.

> **Important:** Before merging this PR, DataDog/datadog-lambda-python#761 must be merged first.

## Test plan
- [ ] Existing IAST vulnerability tests pass (they call `VulnerabilityBase.report()` which now delegates to `get_caller_frame_info()`)
- [ ] IAST cookie tests pass (`insecure_cookie.py` now uses shared function)
- [ ] `test_weak_hash.py` edge case test passes with updated mock target

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: alberto.vara <alberto.vara@datadoghq.com>
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 7, 2026
)

## Summary
- Move the native `_stacktrace` C extension from `ddtrace/appsec/_iast/` to `ddtrace/appsec/_shared/` so it can be reused by both IAST and SCA without creating a dependency from SCA into IAST internals.
- Update all imports, build configuration (`setup.py`), and test references to use the new `ddtrace.appsec._shared._stacktrace` path.

Split out from #17156 to keep PRs incremental and reviewable.

> **Important:** Before merging this PR, DataDog/datadog-lambda-python#761 must be merged first, since `datadog-lambda-python` imports `ddtrace.appsec._iast._stacktrace` and needs to be updated to the new path.

## Test plan
- [ ] Existing IAST stacktrace tests pass (`tests/appsec/iast/test_stacktrace.py`)
- [ ] IAST memcheck tests pass (`tests/appsec/iast_memcheck/test_iast_mem_check.py`)
- [ ] Architecture loading module test passes (`tests/appsec/architectures/test_appsec_loading_modules.py`)
- [ ] Serverless import test passes (`tests/internal/test_serverless.py`)
- [ ] Native C extension builds correctly from new path

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: alberto.vara <alberto.vara@datadoghq.com>
@avara1986 avara1986 force-pushed the avara1986/sca-telemetry-rereporting-and-module branch 3 times, most recently from c9fcd49 to 71fdc56 Compare April 9, 2026 12:37
Implements Runtime SCA Reachability — the tracer reports which vulnerable
symbols have actually been invoked at runtime, reducing false positives
from static SCA analysis.

- DependencyEntry model with reachability metadata tracking
- DependencyTracker for heartbeat-based dependency reporting
- Skip re-report scan when SCA is disabled (idle heartbeat optimization)
- CVE loader, registry, resolver, and instrumenter for SCA hooks
- SCA product integration with telemetry writer
- SLO benchmark suite (benchmarks/telemetry_dependencies/)
- Standalone benchmark scripts (perf_bench_heartbeat_cycles/sca_telemetry)
- Riot env and suitespec entries for SCA tests and benchmarks
- Flask integration test for SCA telemetry via testagent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@avara1986 avara1986 force-pushed the avara1986/sca-telemetry-rereporting-and-module branch from 39f37ce to 15db88d Compare April 9, 2026 13:50
avara1986 and others added 10 commits April 9, 2026 16:00
…mpty

When _get_caller_info() returns empty (e.g., deep wrapt/gevent stack
where the native C frame walker can't find user code), the hook now
falls back to the target function's own qualified name (module path +
symbol) instead of passing empty path to attach_dependency_metadata.

Previously, empty path caused add_metadata's `if path` guard to silently
drop the finding, leaving the reached array permanently empty — even
though the hook was firing correctly.

Adds test_instrumenter.py with 8 tests covering:
- inject_hook fires on direct calls and through wrapt wrappers
- Full SCA detection hook → registry → telemetry flow
- Caller info propagation to reached array
- Fallback behavior when caller info is unavailable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds execution_time and max_rss_usage thresholds for the 8 telemetry
dependency reporting scenarios. Thresholds set with ~3-5x headroom
over observed local measurements to account for CI variability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On Python <3.11, co_firstlineno points to the `def` line which has no
bytecode instructions. inject_hook needs the first instruction's line
(the function body). Added _first_instr_line() helper that handles the
cross-version difference (starts_line is int on <3.12, bool on >=3.12).

Also fixes the test to use the same helper instead of co_firstlineno.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
os.register_at_fork(after_in_child=...) callbacks fire AFTER ddtrace's
forksafe mechanism calls product.restart(). This meant:
1. restart() ran and set up _registry
2. CPython fork callback wiped _registry=None
3. _registry was never set again — hook silently returned

Fix: Remove os.register_at_fork from _instrumenter.py and _registry.py.
Instead, restart() in product.py explicitly calls both reset functions
before re-initializing, ensuring correct ordering.

Adds 3 tests for the fork callback ordering guarantee.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@avara1986 avara1986 force-pushed the avara1986/sca-telemetry-rereporting-and-module branch from f8227fb to 962eb72 Compare April 10, 2026 10:06
Copy link
Copy Markdown

@dastrong dastrong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from the SCA side

Comment thread ddtrace/internal/telemetry/dependency_tracker.py
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Apr 14, 2026
…17514)

## Summary

This PR extracts the telemetry dependency tracking changes from the larger SCA PR (#17156) to reduce its size and make review more manageable.

- Introduces `DependencyTracker` to manage dependency state, deduplication, and re-reporting logic for SCA telemetry
- Refactors dependency collection out of the telemetry writer into a dedicated module
- Updates the benchmark scenario for `packages_update_imported_dependencies`
- Adds comprehensive tests for the new dependency tracker and updated dependency logic

**Parent PR:** #17156 — `feat(sca): runtime SCA reachability`

## Test plan
- [ ] Existing telemetry tests pass
- [ ] New `tests/telemetry/test_dependency.py` tests pass
- [ ] `tests/telemetry/test_data.py` tests pass
- [ ] Benchmark scenario runs without errors

## Checklist
- [x] PR description/title adhere to [contributing guidelines](https://ddtrace.readthedocs.io/en/stable/contributing.html)
- [x] Tests provided or no tests needed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: alberto.vara <alberto.vara@datadoghq.com>
@avara1986 avara1986 marked this pull request as ready for review April 15, 2026 10:05
@avara1986 avara1986 requested review from a team as code owners April 15, 2026 10:05
@avara1986 avara1986 requested a review from juanjux April 15, 2026 10:05
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 639230db3a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread ddtrace/internal/sca/product.py Outdated
Comment thread ddtrace/appsec/sca/_instrumenter.py
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot merged commit 57eb721 into main Apr 17, 2026
1140 checks passed
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot deleted the avara1986/sca-telemetry-rereporting-and-module branch April 17, 2026 08:57
juanjux pushed a commit that referenced this pull request Apr 17, 2026
## Summary

The `telemetry_dependencies` benchmark was failing against the baseline
wheel after #17156 merged, with:

```
ModuleNotFoundError: No module named 'ddtrace.internal.telemetry.dependency'
```

Root cause: `scenario._run_old_api` had a function-scope
`from ddtrace.internal.telemetry.dependency import DependencyEntry as
DE`
that Python evaluates on every call. The baseline wheel predates the
SCA-reachability PR, so that module does not exist and the import
crashes before any phase branching. The `else` branch also populated
`already_imported` with `DependencyEntry` instances, but the baseline's
`update_imported_dependencies(already_imported: Dict[str, str], ...)`
expects version strings — it would break if ever exercised.

## Changes

- Drop the broken top-level import.
- Rewrite the idle/fallback branch to populate `already_imported`
  as `{name: version_str}`, matching the baseline contract.

The candidate (new-API) path is unaffected — it runs
`_run_new_api` because `HAS_DEPENDENCY_TRACKER` is True on current
`main`.

## Test plan

- [ ] Re-run the benchmark platform job for `telemetry_dependencies`
      and confirm it completes for both baseline and candidate.
- [ ] Spot-check that the `telemetry_add_metric` job (which was
      already passing) is still unaffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dubloom pushed a commit that referenced this pull request Apr 21, 2026
## Description

Implements **Runtime SCA Reachability** — the tracer reports which vulnerable symbols (functions/methods in third-party libraries with known CVEs) have actually been invoked at runtime, reducing false positives from static SCA analysis.

**RFC**: https://docs.google.com/document/d/1xDw9iG6h41VCEgJGTqoJdruRaNS4pYgNifO6nhiizWA/edit?tab=t.a9gurws0d8ua

### How it works

When `DD_APPSEC_SCA_ENABLED=true`:

1. **CVE data loading** — At tracer startup, reads `_cve_data.json` containing vulnerability targets (symbol + CVE + version constraint). Filters against installed packages.
2. **Runtime instrumentation** — For each applicable CVE target, applies bytecode injection (`inject_hook`) to the vulnerable function. Supports both eager (already-imported modules) and lazy (via `ModuleWatchdog` for deferred imports).
3. **CVE registration** — Immediately registers all applicable CVEs on their dependencies with `reached: []` in the telemetry `app-dependencies-loaded` payload. The backend knows which CVEs apply before any symbol is hit.
4. **Reachability detection** — When an instrumented function executes, the hook captures the caller's file path, method name, and line number, then attaches it to the CVE's `reached` array. Only the first occurrence is reported per CVE (RFC: "reporting a single occurrence is sufficient").
5. **Telemetry reporting** — On each heartbeat (default 60s), dependencies with new reachability data are re-reported with all their metadata via `app-dependencies-loaded`.

### Telemetry payload (RFC v3)

```json
{
  "request_type": "app-dependencies-loaded",
  "payload": {
    "dependencies": [
      {
        "name": "requests",
        "version": "2.31.0",
        "metadata": [
          {
            "type": "reachability",
            "value": "{\"id\":\"CVE-2024-35195\",\"reached\":[{\"path\":\"myapp/views.py\",\"method\":\"handle_request\",\"line\":42}]}"
          }
        ]
      }
    ]
  }
}
```

Before any symbol is hit, CVEs are reported with `"reached":[]`. When a symbol executes, the first caller info is added to the `reached` array.

## Performance

Benchmark: `scripts/perf_bench_heartbeat_cycles.py`

Measures `collect_report()` execution time per heartbeat cycle under different scenarios. The overhead is paid only in the background telemetry thread (every 60s), never in user request paths.

- **SCA OFF (main)**: baseline on `main` branch — old `update_imported_dependencies()` path, no `DependencyTracker`, no re-report scan
- **SCA OFF**: this branch with `DD_APPSEC_SCA_ENABLED=false` — new `DependencyTracker` with `metadata=None`, re-report scan skipped
- **SCA ON**: this branch with `DD_APPSEC_SCA_ENABLED=true` — new `DependencyTracker` with `metadata=[]`
- **Overhead**: `(SCA ON − SCA OFF) / SCA OFF`

### 1,000 dependencies (typical large application)

| Heartbeat Cycle | SCA OFF (main) | SCA OFF | SCA ON | Overhead |
|---|---|---|---|---|
| First heartbeat (all new) | 4.56ms | 4.63ms | 5.10ms | **+10.1%** |
| Idle (nothing to report) | 0.2us | 72.2us | 239.6us | **+231.8%** |
| CVE registration (100 CVEs, reached=[]) | 0.3us | 73.5us | 1.20ms | **+1527.5%** |
| SCA hits (100 hits on 50 deps) | 0.3us | 73.7us | 1.44ms | **+1857.1%** |

### 10,000 dependencies (extreme scale)

| Heartbeat Cycle | SCA OFF (main) | SCA OFF | SCA ON | Overhead |
|---|---|---|---|---|
| First heartbeat (all new) | 53.15ms | 57.18ms | 62.12ms | **+8.6%** |
| Idle (nothing to report) | 0.3us | 742.6us | 2.20ms | **+195.7%** |
| CVE registration (1,000 CVEs, reached=[]) | 0.3us | 720.7us | 13.51ms | **+1774.4%** |
| SCA hits (1,000 hits on 500 deps) | 0.3us | 718.9us | 15.56ms | **+2064.2%** |

### Payload size

| Scenario (1,000 deps) | Entries | Size |
|---|---|---|
| First heartbeat SCA OFF | 1,000 | 62 KB |
| First heartbeat SCA ON | 1,000 | 62 KB |
| CVE registration (100 CVEs) | 50 | 10 KB |
| SCA hits (100 hits) | 50 | 16 KB |

### Memory overhead

| Scenario (1,000 deps) | SCA OFF | SCA ON | Delta |
|---|---|---|---|
| Idle heartbeat | 155.3 KB | 192.5 KB | +37.2 KB |
| CVE registration (100 CVEs) | 136.4 KB | 205.8 KB | +69.4 KB |
| SCA hits (100 hits) | 136.2 KB | 208.5 KB | +72.3 KB |

> **Note on overhead**: The percentage overhead for idle, CVE registration, and SCA hits appears very high because the SCA OFF baseline includes mock/benchmark harness overhead (~72us at 1K deps) that dominates the measurement. In absolute terms:
>
> - **First heartbeat**: nearly identical across all three columns (4.56ms → 4.63ms → 5.10ms at 1K deps), confirming the `DependencyTracker` refactor adds **minimal overhead** to initial dependency discovery.
> - **Idle heartbeat with SCA OFF**: ~72us includes benchmark mock overhead; measured independently at ~8us (lock acquisition + `get_newly_imported_modules()` + lazy config check). The re-report scan is **completely skipped** when SCA is disabled.
> - **SCA ON worst case** at 1,000 dependencies: **1.44ms per 60s heartbeat** — 0.002% of the cycle.
> - **SCA ON worst case** at 10,000 dependencies with 1,000 CVEs: **16ms** — 0.027% of the heartbeat interval.
>
> All overhead runs entirely in the background telemetry thread and does not affect user request latency.

### SLO benchmark

A CI-integrated benchmark suite is available at `benchmarks/telemetry_dependencies/` with 8 scenarios covering first/idle/cve/hits phases at 100 and 1,000 dependencies. It is triggered automatically when `ddtrace/internal/telemetry/dependency*.py` or `ddtrace/appsec/sca/*` files change and compares performance between the base branch and this PR.

## Risks

- **Bytecode injection**: Uses the existing `inject_hook` infrastructure from dd-trace-py. The hook is exception-safe (wrapped in try/except) and never raises in user code.
- **Memory**: `DependencyEntry` objects add ~150 bytes per dependency vs plain strings. At 1,000 deps this is ~150KB total — negligible.
- **Lock contention**: The `DependencyTracker._lock` is held briefly during `attach_metadata` calls from the SCA hook. After the first hit per CVE (max reached=1), subsequent hook invocations short-circuit before any lock acquisition.

## Additional Notes

- Merge this PR first: DataDog/datadog-lambda-python#761
- Previous model PR benchmarks: #17092
- The static CVE JSON (`_cve_data.json`) will be replaced by Remote Config in the long-term solution

Co-authored-by: alberto.vara <alberto.vara@datadoghq.com>
dubloom pushed a commit that referenced this pull request Apr 21, 2026
## Summary

The `telemetry_dependencies` benchmark was failing against the baseline
wheel after #17156 merged, with:

```
ModuleNotFoundError: No module named 'ddtrace.internal.telemetry.dependency'
```

Root cause: `scenario._run_old_api` had a function-scope
`from ddtrace.internal.telemetry.dependency import DependencyEntry as
DE`
that Python evaluates on every call. The baseline wheel predates the
SCA-reachability PR, so that module does not exist and the import
crashes before any phase branching. The `else` branch also populated
`already_imported` with `DependencyEntry` instances, but the baseline's
`update_imported_dependencies(already_imported: Dict[str, str], ...)`
expects version strings — it would break if ever exercised.

## Changes

- Drop the broken top-level import.
- Rewrite the idle/fallback branch to populate `already_imported`
  as `{name: version_str}`, matching the baseline contract.

The candidate (new-API) path is unaffected — it runs
`_run_new_api` because `HAS_DEPENDENCY_TRACKER` is True on current
`main`.

## Test plan

- [ ] Re-run the benchmark platform job for `telemetry_dependencies`
      and confirm it completes for both baseline and candidate.
- [ ] Spot-check that the `telemetry_add_metric` job (which was
      already passing) is still unaffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/no-changelog A changelog entry is not required for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants