Skip to content

chore(ci): apply 48h cooldown to dependabot and riot lockfile updates - #18182

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 17 commits into
mainfrom
juanjux/APMLP-1359-supply-chain-cooldowns
Jun 16, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 17 commits into
mainfrom
juanjux/APMLP-1359-supply-chain-cooldowns

Conversation

@juanjux

@juanjux juanjux commented May 20, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Depends on the next riot version (0.22.0) so not mergeable until that one has been released and scripts/update-ci-dependencies has been run!

Summary

Implements the cross-language supply-chain hardening "cooldown" controls documented in epic APMLP-1343 for dd-trace-py. The 48h cooldown is now enforced everywhere Dependabot or our daily test-lockfile job would otherwise pull in a freshly published release, including transitive dependencies pulled in by lockfile recompilation.

Tickets addressed:

  • APMLP-1359 — GHA-CD: added a cooldown block to the existing github-actions entry in .github/dependabot.yml. GitHub Actions are already SHA-pinned (the existing GHA-PIN work); this adds the missing 48h delay before proposing an update.
  • APMLP-1360 — DOCKER-CD: added new docker and docker-compose ecosystems to .github/dependabot.yml for docker/, benchmarks/, lib-injection/, the root docker-compose*.yml files, with the same 48h cooldown. This replaces a fully manual digest-rotation flow with cooldown-aware automation. (Tightening DOCKER-PIN on the unpinned docker-compose.yml images, e.g. mysql:5.7, redis:4.0-alpine, etc., is intentionally out of scope here and would be a follow-up.)
  • APMLP-1362 — TEST-CD: three layers of cooldown enforcement on riot test lockfile updates:
    1. Trigger — scripts/freshvenvs.py ignores PyPI releases that are less than COOLDOWN_DAYS (= 2) old when deciding whether the lockfiles are outdated. Falls back to the absolute latest if every candidate is too fresh so detection is never silently disabled.
    2. Transitive Deps — the Run regenerate-riot-latest workflow step sets RIOT_PIP_COMPILE_BACKEND=uv and RIOT_PIP_COMPILE_EXCLUDE_NEWER=<cutoff> (computed as now - 48h). With the riot change in DataDog/riot#267 this tells riot to resolve the lockfile via uv pip compile --exclude-newer=<cutoff> so transitive dependencies younger than the cooldown cannot enter the lockfile in the first place.
    3. Validator — scripts/check_lockfile_cooldown.py walks the regenerated lockfiles after compile, queries PyPI for the upload time of every name==version pin, and exits non-zero if any release is younger than COOLDOWN_DAYS. It is invoked from scripts/regenerate-riot-latest.sh immediately after compile-and-prune-test-requirements, so the workflow fails before opening an update PR if a fresh transitive pin ever slips through (e.g. because we are still on an older riot, or because someone disables the uv backend).

Implements the cross-language supply-chain hardening "cooldown" controls
documented in APMLP-1343 for Python (dd-trace-py).

- GHA-CD (APMLP-1359): adds a 48h `cooldown` block to the existing
  `github-actions` ecosystem in `.github/dependabot.yml` so Dependabot
  never proposes an update to a release that is less than two days old.
  Major bumps wait 7 days for extra safety.

- DOCKER-CD (APMLP-1360): adds new `docker` and `docker-compose`
  ecosystems to Dependabot for the Dockerfiles in `docker/`,
  `benchmarks/`, `lib-injection/` and the `docker-compose*.yml` files,
  all with the same 48h cooldown. This gives us automated digest
  rotation that respects the cooldown instead of the previous fully
  manual process.

- TEST-CD (APMLP-1362): teaches `scripts/freshvenvs.py` to ignore PyPI
  releases that are less than `COOLDOWN_DAYS` (= 2) old when deciding
  whether the riot test lockfiles are out of date. The daily
  `generate-package-versions.yml` workflow now waits 48h after a
  release before regenerating a riot lockfile against it. Falls back
  to the absolute latest if every candidate is too fresh so detection
  is never silently disabled.

Known limitation captured in APMLP-1362: riot uses `python -m piptools
compile` (pip-tools, not uv) and pip-tools has no `--exclude-newer`
flag, so transitive dependencies of a triggered direct update can
still be < 48h old. A follow-up will either switch riot to
`uv pip compile --exclude-newer` or add a post-compile validator.

APMLP-1361 (DEP-PIN) is intentionally not implemented: ddtrace is a
library and its runtime dependencies must remain version ranges so
they coexist with the customer's installed versions; PyPI's immutable
releases provide the equivalent protection against tag-mutation
attacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
@juanjux
juanjux requested review from a team as code owners May 20, 2026 08:01
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented May 20, 2026 •

Copy link
Copy Markdown

Codeowners resolved as

.github/dependabot.yml                                                  @DataDog/python-guild @DataDog/apm-core-python
.github/workflows/generate-package-versions.yml                         @DataDog/python-guild @DataDog/apm-core-python
.github/workflows/validate-dependabot.yml                               @DataDog/python-guild @DataDog/apm-core-python
ci/requirements/ci.in                                                   @DataDog/apm-core-python
scripts/check_lockfile_cooldown.py                                      @DataDog/apm-core-python
scripts/freshvenvs.py                                                   @DataDog/apm-core-python
scripts/regenerate-riot-latest.sh                                       @DataDog/apm-core-python
scripts/validate_dependabot_config.py                                   @DataDog/apm-core-python
tests/internal/test_check_lockfile_cooldown.py                          @DataDog/apm-core-python

@datadog-official

datadog-official Bot commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

Pipelines  Tests

✨ Fix all issues with BitsAI

⚠️ Warnings

🚦 8 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-py | build linux serverless: [arm64, cp315-cp315, v113741357-d2b8243-manylinux2014_aarch64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux serverless: [arm64, cp315-cp315, v113741589-d2b8243-musllinux_1_2_aarch64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux: [amd64, cp315-cp315, v113741238-d2b8243-manylinux2014_x86_64]   View in Datadog   GitLab

View all 8 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a97dc56 | Docs | Datadog PR Page | Give us feedback!

juanjux and others added 2 commits May 20, 2026 10:21
Closes the transitive-dependency gap on TEST-CD (APMLP-1362). The
previous commit applied the 48h cooldown at the "outdated detection"
level only; this commit adds two complementary mechanisms so freshly
published transitive dependencies cannot make it into a regenerated
.riot/requirements/*.txt either.

1. uv pip compile backend (defense-in-front):
   Sets RIOT_PIP_COMPILE_BACKEND=uv and RIOT_PIP_COMPILE_EXCLUDE_NEWER
   (a cutoff 48h in the past) on the `Run regenerate-riot-latest`
   step of `generate-package-versions.yml`. With the riot change in
   DataDog/riot#267 these tell riot to resolve dependencies via
   `uv pip compile --exclude-newer=<cutoff>`. Older riot versions
   ignore both variables, so it is safe to set them before the riot
   bump lands.

2. Post-compile validator (defense-in-depth):
   Adds scripts/check_lockfile_cooldown.py, which walks the
   regenerated lockfiles, queries PyPI for the upload time of every
   `name==version` pin, and exits non-zero if any release is younger
   than COOLDOWN_DAYS (= 2). Wired into regenerate-riot-latest.sh
   immediately after compile-and-prune-test-requirements so the
   workflow fails before opening an update PR if a transitive bypass
   ever slips through.

Tests cover the lockfile parser, the cooldown decision logic, and
both pass / fail paths via `tests/internal/test_check_lockfile_cooldown.py`.

Refs APMLP-1362, depends on DataDog/riot#267.

Co-authored-by: Cursor <cursoragent@cursor.com>
…release)

The TEST-CD layer-2 (uv pip compile --exclude-newer) only takes effect
once we are on a riot version that ships the new
RIOT_PIP_COMPILE_BACKEND / RIOT_PIP_COMPILE_EXCLUDE_NEWER env vars
(DataDog/riot#267, merged into master as c04e0aa). The next riot
release will be 0.22.0 (semver minor bump for a feat: commit on top
of 0.21.0).

This commit:
- Bumps RIOT_VERSION in docker/Dockerfile from 0.21.0 to 0.22.0.
- Bumps riot in ci/requirements/ci.in from 0.20.1 to 0.22.0.

ci/requirements/ci.txt is intentionally NOT regenerated yet because
riot 0.22.0 is not on PyPI yet (uv pip compile --generate-hashes
fails with "No solution found"). Before merging this PR a maintainer
must:

  1. Wait for riot 0.22.0 to be cut and uploaded to PyPI.
  2. Run scripts/update-ci-dependencies to regenerate ci.txt with the
     new pin and hashes.
  3. Commit the regenerated ci.txt.

The dd-trace-py CI does not enforce ci.in/ci.txt sync (the
check-ci-dependencies job only validates that ci.txt is internally
consistent under --require-hashes), so this commit is safe to push
while we wait for the release.

Co-authored-by: Cursor <cursoragent@cursor.com>
@juanjux juanjux self-assigned this May 20, 2026
@juanjux juanjux added the manual merge Do not automatically merge label May 20, 2026
@pr-commenter

pr-commenter Bot commented May 20, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-05-21 07:53:05

Comparing candidate commit a0bbc33 in PR branch juanjux/APMLP-1359-supply-chain-cooldowns with baseline commit 874a5d0 in branch main.

Found 0 performance improvements and 4 performance regressions! Performance is the same for 616 metrics, 10 unstable metrics.

scenario:iastaspects-lstrip_aspect

  • 🟥 execution_time [+62.267µs; +68.027µs] or [+22.908%; +25.027%]

scenario:iastaspects-translate_aspect

  • 🟥 execution_time [+62.803µs; +68.695µs] or [+12.726%; +13.920%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+93.208µs; +100.925µs] or [+22.025%; +23.849%]

scenario:span-start

  • 🟥 execution_time [+1.204ms; +1.374ms] or [+7.649%; +8.728%]

Resolved docker/Dockerfile conflict: kept RIOT_VERSION=0.22.0 from this
branch and UV_VERSION=0.11.14 from main.

Co-authored-by: Cursor <cursoragent@cursor.com>

@emmettbutler emmettbutler left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like a solid security improvement

@juanjux

juanjux commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-06-15 10:00:34 UTC ℹ️ Start processing command /merge


2026-06-15 10:00:39 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in main is approximately 58m (p90).


2026-06-15 11:35:46 UTC ❌ MergeQueue: The checks failed on this merge request

Tests failed on this commit 1e6f4b8:

What to do next?

  • Investigate the failures and when ready, re-add your pull request to the queue!
  • If your PR checks are green, try to rebase/merge. It might be because the CI run is a bit old.
  • Any question, go check the FAQ.

juanjux and others added 2 commits June 15, 2026 15:11
…r ecosystems

The github-actions, docker, and docker-compose ecosystems do not support
the semver-major/minor/patch-days cooldown keys; only default-days is
allowed. These keys are rejected by Dependabot's config validation, which
runs in the merge queue, so keep default-days: 2 only.

Co-authored-by: Cursor <cursoragent@cursor.com>
GitHub's native Dependabot config validator only reliably runs against the
merge queue's merge commit, so invalid configs (such as semver-*-days cooldown
keys on non-semver ecosystems) are surfaced at merge time rather than on PR CI.

Add a validate-dependabot workflow that runs on PRs touching the config. It
performs structural JSON-schema validation plus a self-contained guard
(scripts/validate_dependabot_config.py) for the ecosystem-specific cooldown
rule that the public schema does not encode.

Co-authored-by: Cursor <cursoragent@cursor.com>
juanjux added 2 commits June 16, 2026 10:22
The new validate-dependabot workflow installed pyyaml and
check-jsonschema directly, which triggers the check_ci_dependencies job
("Direct pip install detected"). Both packages are already pinned with
== and are only used by this one workflow, so adding them to
ci/requirements/ci.txt would be overkill.

Use the documented `# ci-deps: allow` exception (which requires version
specifiers — already satisfied) following the same pattern as
.gitlab/package.yml:434.

Signed-off-by: Juanjo Alvarez <juanjo.alvarezmartinez@datadoghq.com>
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit f4e8000 into main Jun 16, 2026
500 of 502 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the juanjux/APMLP-1359-supply-chain-cooldowns branch June 16, 2026 11:11
gh-worker-dd-mergequeue-cf854d Bot pushed a commit that referenced this pull request Jun 23, 2026
## Description

Output of running `scripts/update-ci-dependencies --compile --update-workflows`.

This should restore the `Update riot lockfiles` workflow’s cooldown behavior added in #18182, since the workflow
installs CI tools from `ci/requirements/ci.txt`.



Co-authored-by: louis.tricot <louis.tricot@datadoghq.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. manual merge Do not automatically merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants