Skip to content

test(appsec): enable appsec_integrations_fastapi on Python 3.15 - #19853

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
avara1986/py315-appsec-integrations-fastapi
Aug 26, 2026
Merged

test(appsec): enable appsec_integrations_fastapi on Python 3.15#19853
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
avara1986/py315-appsec-integrations-fastapi

Conversation

@avara1986

@avara1986 avara1986 commented Aug 25, 2026

Copy link
Copy Markdown
Member

Description

Part of the Python 3.15 integration parity effort (parent tracker: #17809).

Closes #17844

APPSEC-69809

This PR enables the appsec_integrations_fastapi suite on Python 3.15.

There was no single upstream pin to bump. The row's own premise ("real blocker is likely IAST
runtime") was resolved by #19698, and the issue text is partly stale: it lists two capped
sub-venvs (==0.86.0, ==0.94.1), but #19620 replaced the 0.94.1 one with ==0.141.1 on
["3.10", "3.14"], leaving only ==0.86.0 capped at max_version="3.13". That cap turned out to
be liftable — fastapi 0.86.0 resolves pydantic 1.10.26, which publishes a pure py3 wheel, so it
installs and passes on both 3.14 and 3.15. The remaining work was unpinning the two dependencies
that can never resolve on 3.15, and fixing a tests/conftest.py fixture that makes every test in
the repository error at setup on 3.15.

Changes

  • riotfile.py
    • fastapi==0.86.0 venv: select_pys(min_version="3.9", max_version="3.13")select_pys(min_version="3.9").
    • mcp: ==1.20.0==1.21.2. mcp 1.20.0 imports pydantic._internal._typing_extra.eval_type_backport, which pydantic removed on main, so the pinned mcp cannot coexist with any pydantic that supports 3.15. 1.24+ was rejected: its transport-security middleware answers 421 Misdirected Request to the SSE tests' 0.0.0.0 Host header (4 failures). 1.21.2 is the first release that drops the private import while keeping the API the tests use.
    • pydantic: ~=2.12.1~=2.12. 2.12.x has no cp315 wheels and never will, so a minor-locked pin blocks 3.15 permanently. The >=2.12 floor (first release with cp314 wheels, added in ci(tests): enable Python 3.14 integration tests for IAST #15657) is preserved.
    • Two short comments recording why each pin is where it is, so the next bump doesn't rediscover the 421 the hard way.
  • .riot/requirements/: regenerated — 11 added, 10 removed. The 7 unaffected venvs keep their existing lockfiles. pydantic resolves to 2.13.4 on 3.10–3.14 today.
  • tests/conftest.py: the autouse enable_crashtracking fixture asserted crashtracking.is_started() on Linux, but setup.py gates the Rust crashtracker feature on sys.version_info < (3, 15). On 3.15 the native module is absent, so the assert fired at setup for every test in the repo, not just this suite. Now gated on crashtracking.is_available. This exact guard was already recorded as a hand-off item in the IAST 3.15 work (APPSEC-69649).

No ddtrace runtime code changed — the fastapi and IAST integration code needed nothing for 3.15.

Checklist

  • Bumped upstream pin in riotfile.py to a version that supports Python 3.15 — partially N/A. mcp and pydantic were unpinned/bumped as described above, but no upstream release fixes the actual 3.15 blocker yet (see Risks).
  • Lifted the max_version="3.13" cap on the fastapi==0.86.0 venv.
  • Regenerated and committed the .riot/requirements/*.txt lockfiles (11 added, 10 removed). Verified all 18 venvs of the suite resolve to a lockfile, and that all 1887 venvs repo-wide still do.
  • Ran the suite on 3.15 — see Testing. Note this could not go through scripts/run-tests; see the caveat there.
  • Updated supported_versions.json — N/A. Re-ran scripts/integration_registry/generate_supported_versions.py: no diff, since the tested fastapi versions are unchanged.
  • No release note; PR labeled changelog/no-changelog (test/CI-only changes).

Testing

Suite: tests/appsec/integrations/fastapi_tests/. CPython 3.15.0rc1+dev (pyenv install 3.15-dev,
matching .python-version and .gitlab/testrunner.yml), with #17849 stacked in a scratch worktree to
get past the import ddtrace blocker and requires-python locally widened so pip install -e . would
run. Neither local-only edit is in this PR.

Python fastapi pydantic mcp Result
3.14 0.86.0 1.10.26 51 passed, 5 skipped
3.14 0.114.2 2.13.4 1.21.2 64 passed, 1 skipped
3.14 0.141.1 2.13.4 1.21.2 64 passed, 1 skipped
3.15 0.86.0 1.10.26 51 passed, 5 skipped
3.15 0.141.1 2.14.0b1 (git main) 1.21.2 64 passed, 1 skipped

The 3.14 legs were installed straight from the regenerated lockfiles (13b41ca, f4ebe37, 1db4c48)
with the ddtrace pytest plugin active, i.e. what CI will run. 3.14 and 3.15 give identical counts on
the latest-fastapi venv.

scripts/lint fmt, style, riot, and suitespec-check all pass.

Why raw pytest for these runs. AGENTS.md says never to invoke pytest directly, and I tried
riot first. Two things block it: (a) riot cannot target 3.15 at all — riotfile.py's
SUPPORTED_PYTHON_VERSIONS and scripts/gen_gitlab_config.py's ALL_PYTHON_VERSIONS both stop at
3.14 and there are zero 3.15 lockfiles; (b) scripts/run-tests is currently broken on my host for
this suite regardless of version — riot builds derived venvs under lib/python3.12 (the interpreter
riot itself runs on inside the testrunner image) while the pytest shim resolves the target's
site-packages, so every venv dies with ModuleNotFoundError: No module named '_pytest' in the build
phase. That reproduces on both 13b41ca (3.14) and 1f61c7b (3.13), including after deleting the
derived venvs, so it is not caused by this PR. The env=/pkgs= blocks were replicated by hand from
the venv specs; the 3.14 legs used the committed lockfiles verbatim.

Risks

  • This PR is correct but inert until upstream and Tier A land. The suite still cannot run on 3.15
    in CI:
  • Lockfile churn is real but bounded: pydantic moves 2.12.x → 2.13.4 and mcp 1.20.0 → 1.21.2
    on 3.10–3.14. Both validated on 3.14 across all three fastapi venvs; CI covers 3.10–3.13.
  • The tests/conftest.py guard is repo-wide, not suite-scoped. It cannot mask a crashtracker
    packaging regression: tests/crashtracker/test_crashtracker.py::test_crashtracker_available still
    asserts crashtracking.is_available on Linux and fails loudly if the native module goes missing.
  • Lifting the 0.86.0 cap adds one new CI venv (that venv on 3.14); validated above.

Additional Notes

Hand-off for the tracer-wrapping / ci_visibility 3.15 owners. Once #17849 lands, the ddtrace
pytest plugin will fail to import on 3.15 and no suite will be runnable: that branch stops defining
INJECTION_ASSEMBLY in ddtrace/internal/bytecode_injection/__init__.py on 3.15 (it takes the
sys.monitoring path instead), but ddtrace/internal/coverage/import_instrumentation_py3_12.py:9
imports it unconditionally, so plugin load dies with ImportError: cannot import name 'INJECTION_ASSEMBLY'. I worked around it locally with -p no:ddtrace. This belongs to #17849 or the
ci_visibility rows (#17838#17842), not here.

Follow-up worth filing separately (not 3.15-specific). When pydantic 2.14 releases, the
fastapi ~=0.114.2 venv — which has no pydantic pin — will resolve it on every Python version, and
that combination breaks mcp==1.20.0. The mcp==1.21.2 bump in this PR removes that latent
breakage from this suite, but other suites pinning old mcp may still be exposed.

The fastapi==0.86.0 sub-venv was the only one still capped at 3.13. It
resolves pydantic 1.10.26, which ships a pure py3 wheel, so it installs
and passes on 3.14 and 3.15; lift the cap.

mcp 1.20.0 imports pydantic._internal._typing_extra.eval_type_backport,
removed on pydantic main, so it cannot coexist with any pydantic that
supports 3.15; bump to 1.21.2 (1.24+ answers 421 to the SSE tests' Host
header). pydantic ~=2.12.1 can never resolve a cp315 wheel, so widen it
to ~=2.12. Lockfiles regenerated.

tests/conftest.py asserted crashtracking.is_started() on Linux, but
setup.py drops the Rust crashtracker on 3.15, so every test in the repo
errored at setup there. Guard on crashtracking.is_available;
test_crashtracker_available still asserts it loudly.

APPSEC-69809

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@avara1986 avara1986 added the changelog/no-changelog A changelog entry is not required for this PR. label Aug 25, 2026
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Pipelines  Tests

⚠️ Warnings

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 5 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-py | build linux serverless: [arm64, cp315-cp315, v113741357-d2b8243-manylinux2014_aarch64, 1] — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

DataDog/apm-reliability/dd-trace-py | build linux: [amd64, cp315-cp315, v113741238-d2b8243-manylinux2014_x86_64] — 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

Changelog | Validate changelog

View more details · View in GitHub Actions

Release note not found. Use 'reno new <slug>' to add a new note to 'releasenotes/notes' or add the label 'changelog/no-changelog' to skip this validation.

View all 5 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 2 jobs - 2 passed on retry View in Datadog

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 2f9302c | Docs | View more details | Give us feedback!

@pr-commenter

pr-commenter Bot commented Aug 25, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-25 13:59:49

Comparing candidate commit 2f9302c in PR branch avara1986/py315-appsec-integrations-fastapi with baseline commit 6ba985e in branch main.

📊 Benchmarking dashboard

Found 0 performance improvements and 8 performance regressions! Performance is the same for 575 metrics, 10 unstable metrics, 2 known flaky benchmarks, 16 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:httppropagationinject-ids_only

  • 🟥 execution_time [+2.088µs; +2.211µs] or [+11.199%; +11.856%]

scenario:iastaspects-add_aspect

  • 🟥 execution_time [+14.556µs; +18.169µs] or [+14.366%; +17.932%]

scenario:iastaspects-join_aspect

  • 🟥 execution_time [+50.015µs; +55.964µs] or [+23.631%; +26.441%]

scenario:iastaspects-title_aspect

  • 🟥 execution_time [+61.193µs; +66.931µs] or [+22.691%; +24.819%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+144.274µs; +150.479µs] or [+35.081%; +36.590%]

scenario:iastaspectssplit-rsplit_aspect

  • 🟥 execution_time [+15.965µs; +21.667µs] or [+10.896%; +14.788%]

scenario:telemetryaddmetric-1-count-metric-1-times

  • 🟥 execution_time [+417.656ns; +456.978ns] or [+15.345%; +16.790%]

scenario:tracer-small

  • 🟥 execution_time [+24.555µs; +27.525µs] or [+7.245%; +8.122%]

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:coreapiscenario-context_with_data_listeners

  • unstable execution_time [-690.419ns; +793.888ns] or [-6.260%; +7.198%]

scenario:coreapiscenario-core_dispatch_1_listener

  • unstable execution_time [-34.266ns; +31.717ns] or [-5.605%; +5.188%]

scenario:coreapiscenario-core_dispatch_50_listeners

  • unstable execution_time [-1692.425ns; +1638.330ns] or [-9.869%; +9.554%]

scenario:coreapiscenario-core_dispatch_exception_listeners

  • unstable execution_time [-1160.748ns; +1304.117ns] or [-9.027%; +10.142%]

scenario:coreapiscenario-core_dispatch_listeners

  • unstable execution_time [-336.095ns; +318.916ns] or [-9.123%; +8.657%]

scenario:coreapiscenario-core_dispatch_no_args_listeners

  • unstable execution_time [-280.352ns; +228.924ns] or [-9.561%; +7.807%]

scenario:coreapiscenario-core_dispatch_with_results_1_listener

  • unstable execution_time [-82.053ns; +63.630ns] or [-7.208%; +5.590%]

scenario:coreapiscenario-core_dispatch_with_results_50_listeners

  • unstable execution_time [-3173.521ns; +4834.206ns] or [-7.850%; +11.958%]

scenario:coreapiscenario-core_dispatch_with_results_listeners

  • unstable execution_time [-809.945ns; +698.231ns] or [-10.070%; +8.681%]

scenario:packagesupdateimporteddependencies-import_many_stdlib_cached

  • unstable execution_time [-60.228µs; +57.601µs] or [-9.621%; +9.201%]

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:iastaspects-ljust_noaspect

  • 🟥 execution_time [+60.745µs; +65.361µs] or [+21.370%; +22.994%]

scenario:span-start

  • 🟥 execution_time [+1.336ms; +1.525ms] or [+8.818%; +10.067%]

Known flaky benchmarks without significant changes:

  • scenario:errortrackingflasksqli-baseline
  • scenario:flasksimple-iast-get
  • scenario:iastaspects-casefold_aspect
  • scenario:iastaspects-casefold_noaspect
  • scenario:iastaspects-index_aspect
  • scenario:iastaspects-lower_aspect
  • scenario:iastaspects-replace_aspect
  • scenario:iastaspects-swapcase_aspect
  • scenario:iastaspects-title_noaspect
  • scenario:iastaspects-translate_aspect
  • scenario:iastaspects-translate_noaspect
  • scenario:iastaspects-upper_noaspect
  • scenario:packagespackageforrootmodulemapping-cache_off
  • scenario:packagespackageforrootmodulemapping-cache_on
  • scenario:sethttpmeta-all-enabled
  • scenario:telemetryaddmetric-record-100-metrics

@avara1986
avara1986 marked this pull request as ready for review August 25, 2026 15:07
@avara1986
avara1986 requested review from a team as code owners August 25, 2026 15:07
@avara1986
avara1986 requested a review from Yun-Kim August 25, 2026 15:07

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

Copy link
Copy Markdown

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: 2f9302cd01

ℹ️ 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 tests/conftest.py
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit 6ba690d into main Aug 26, 2026
1284 of 1285 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the avara1986/py315-appsec-integrations-fastapi branch August 26, 2026 08:27
@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against main using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

No remaining files require a CODEOWNERS review.

@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 249 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 249 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=135)
ddtrace.llmobs._integrations.google_adk -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.internal.ci_visibility.recorder -×-> ddtrace.trace  (product:ci_visibility -> product:tracing, score=133)
ddtrace.llmobs._integrations.langgraph -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.llmobs._integrations.litellm -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 3 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector
ddtrace.llmobs -> ddtrace.llmobs._evaluators -> ddtrace.llmobs._evaluators.format -> ddtrace.llmobs._experiment -> ddtrace.llmobs
ddtrace.appsec._asm_request_context -> ddtrace.appsec._iast._iast_request_context_base -> ddtrace.appsec._iast._iast_env -> ddtrace.appsec._iast.reporter -> ddtrace.appsec._exploit_prevention.stack_traces -> ddtrace.appsec._asm_request_context

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.

[3.15] appsec_integrations_fastapi — enable on Python 3.15

2 participants