Skip to content

Commit 3418718

Browse files
authored
Merge branch 'master' into fix/okhttp-virtual-thread-dispatcher-trace-contamination
2 parents 269f42c + 93c8609 commit 3418718

1,007 files changed

Lines changed: 35462 additions & 25348 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/add-apm-integrations/SKILL.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ pattern before writing new code. Use it as a template.
6363
- `testImplementation` dependencies for tests
6464
- `muzzle { pass { } }` directives (see Step 9)
6565
4. Register the new module in `settings.gradle.kts` in **alphabetical order**
66+
5. Register the integration name in `metadata/supported-configurations.json`, or
67+
`checkInstrumenterModuleConfigurations` fails. The name in `super(...)` maps to env var
68+
`DD_TRACE_<NAME>_ENABLED` (`.` and `-` become `_`, uppercased — `couchbase-3`
69+
`DD_TRACE_COUCHBASE_3_ENABLED`). Add a `"type": "boolean"` entry, in alphabetical order, with
70+
aliases `DD_TRACE_INTEGRATION_<NAME>_ENABLED` and `DD_INTEGRATION_<NAME>_ENABLED`. Set `default`
71+
to the module's real default — `"true"`, or `"false"` if it overrides `defaultEnabled()` (e.g.
72+
OpenTelemetry, Hazelcast). Declaring several names (`super("a", "b")`) means one entry each.
6673

6774
## Step 5 – Write the InstrumenterModule
6875

@@ -193,11 +200,15 @@ Run these commands in order and fix any failures before proceeding:
193200
./gradlew :dd-java-agent:instrumentation:$framework-$version:muzzle
194201
./gradlew :dd-java-agent:instrumentation:$framework-$version:test
195202
./gradlew :dd-java-agent:instrumentation:$framework-$version:latestDepTest
203+
./gradlew checkInstrumenterModuleConfigurations
196204
./gradlew spotlessCheck
197205
```
198206

199207
**If muzzle fails:** check for missing helper class names in `helperClassNames()`.
200208

209+
**If `checkInstrumenterModuleConfigurations` fails:** an integration name from `super(...)` is missing
210+
(or mismatched) in `metadata/supported-configurations.json` — see Step 4, item 5.
211+
201212
**If tests fail:** verify span lifecycle order (start → activate → error → finish → close), helper registration,
202213
and `contextStore()` map entries match actual usage.
203214

@@ -208,6 +219,7 @@ and `contextStore()` map entries match actual usage.
208219
Output this checklist and confirm each item is satisfied:
209220

210221
- [ ] `settings.gradle.kts` entry added in alphabetical order
222+
- [ ] `metadata/supported-configurations.json` has a `DD_TRACE_<NAME>_ENABLED` entry (+ the two aliases) for every name passed to `super(...)`
211223
- [ ] `build.gradle` has `compileOnly` deps and `muzzle` directives with `assertInverse = true`
212224
- [ ] `@AutoService(InstrumenterModule.class)` annotation present on the module class
213225
- [ ] `helperClassNames()` lists ALL referenced helpers (including inner, anonymous, and enum synthetic classes)

.claude/skills/migrate-groovy-to-java/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ When converting Groovy code to Java code, make sure that:
3333
- Replace `injectSysConfig(key, value)` calls with `@WithConfig` when the key and value are static literals. Put it on the test method for per-test config, or on the class when every test needs it. The `dd.` prefix is added automatically — use the bare key (e.g. `"trace.scope.strict.mode"`, not `"dd.trace.scope.strict.mode"`). For dynamic or parameterized values, keep the imperative `WithConfigExtension.injectSysConfig(key, value)` call.
3434
- Keep inline comments
3535
- Migrate the named Spock clauses if they exist as inline comments in the Java unit test
36+
- When Groovy tests navigate a JSON request body through helpers like `asMap()` / `asLong()` / `asList()`, check whether `json-unit-assertj` (`libs.json.unit.assertj`) is already in the module's build file. If it is, add a method that returns the raw JSON string and use `assertThatJson(json).node("some.nested.field").isEqualTo(value)` directly instead of the map traversal.
37+
- Groovy's `[key: val]` map literals use a `LinkedHashMap`. When the test doesn't care about insertion order, use `singletonMap` for a single entry or `HashMap` for two or more. If a helper method builds these maps, add a two-arg overload rather than scattering `new LinkedHashMap<>()` constructions through test bodies.
3638

3739
TableTest usage
3840
Import: `import org.tabletest.junit.TableTest;`

.github/CODEOWNERS

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
/dd-smoke-tests/vertx-*/ @DataDog/apm-idm-java
2222
/dd-smoke-tests/wildfly/ @DataDog/apm-idm-java
2323

24+
# @DataDog/apm-release-platform
25+
/.gitlab/ @DataDog/apm-release-platform @DataDog/apm-lang-platform-java
26+
/.gitlab-ci.yml @DataDog/apm-release-platform @DataDog/apm-lang-platform-java
27+
2428
# @DataDog/apm-sdk-capabilities-java
2529
/dd-java-agent/agent-otel @DataDog/apm-sdk-capabilities-java
2630
/dd-smoke-tests/log-injection @DataDog/apm-sdk-capabilities-java
@@ -52,8 +56,6 @@
5256

5357
# @DataDog/apm-lang-platform-java
5458
/.github/ @DataDog/apm-lang-platform-java
55-
/.gitlab/ @DataDog/apm-lang-platform-java
56-
/.gitlab-ci.yml @DataDog/apm-lang-platform-java
5759
/benchmark/ @DataDog/apm-lang-platform-java
5860
/components/ @DataDog/apm-lang-platform-java
5961
/dd-java-agent/instrumentation/java/ @DataDog/apm-lang-platform-java
@@ -88,6 +90,8 @@
8890
/dd-trace-api/src/main/java/datadog/trace/api/EventTracker.java @DataDog/asm-java
8991
/internal-api/src/main/java/datadog/trace/api/gateway/ @DataDog/asm-java
9092
/internal-api/src/main/java/datadog/trace/api/http/ @DataDog/asm-java
93+
/internal-api/src/main/java/datadog/trace/api/telemetry/ScaReachability* @DataDog/asm-java
94+
/telemetry/src/main/java/datadog/telemetry/sca/ @DataDog/asm-java
9195
**/appsec/ @DataDog/asm-java
9296
**/*CallSite*.java @DataDog/asm-java
9397
**/*CallSite*.groovy @DataDog/asm-java

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
- Add your completed PR to the merge queue by commenting `/merge`. You can also:
1616
- Customize the commit message associated with the merge with `/merge --commit-message "..."`
1717
- Remove your PR from the merge queue with `/merge -c`
18-
- Skip all merge queue checks with `/merge -f --reason "reason"`; please use this judiciously, as some checks do not run at the PR-level
18+
- Skip all merge queue checks with `/merge -f --reason "reason"`; please use this judiciously, as some checks do not run at the PR-level (note: the PR still needs to be mergeable, this will only skip the pre-merge build)
1919
- Get more information in [this doc](https://datadoghq.atlassian.net/wiki/spaces/DEVX/pages/3121612126/MergeQueue)
2020

2121
Jira ticket: [PROJ-IDENT]

.github/scripts/dependency_age.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from dataclasses import dataclass
1414
from datetime import datetime, timedelta, timezone
1515
from pathlib import Path
16-
from typing import Any
16+
from typing import Any, Callable
1717

1818

1919
GRADLE_VERSIONS_URL = "https://services.gradle.org/versions/all"
@@ -428,25 +428,49 @@ def validate_lockfiles(args: argparse.Namespace) -> int:
428428
print(f"::warning file={relative_path}::{gav}: {'Cannot verify age' if kind == 'unverified' else 'Too new'}. Reverted lockfile to baseline.")
429429

430430
reverted_files = len(violations_by_file)
431-
summary = build_validation_summary(violations_by_file=violations_by_file, replacements_by_file=replacements_by_file, baseline_lockfiles=baseline_lockfiles, min_age_hours=args.min_age_hours)
432-
emit_outputs({"cutoff_at": format_datetime(cutoff), "reverted_files": reverted_files, "summary": summary}, args.github_output)
431+
summary_instrumentation = build_validation_summary(violations_by_file=violations_by_file, replacements_by_file=replacements_by_file, baseline_lockfiles=baseline_lockfiles, min_age_hours=args.min_age_hours, path_filter=is_instrumentation_path)
432+
summary_core = build_validation_summary(violations_by_file=violations_by_file, replacements_by_file=replacements_by_file, baseline_lockfiles=baseline_lockfiles, min_age_hours=args.min_age_hours, path_filter=lambda path: not is_instrumentation_path(path))
433+
emit_outputs(
434+
{
435+
"cutoff_at": format_datetime(cutoff),
436+
"reverted_files": reverted_files,
437+
"summary_core": summary_core,
438+
"summary_instrumentation": summary_instrumentation,
439+
},
440+
args.github_output,
441+
)
433442
print(f"Validated {len(changed)} changed coordinate(s) across {len(changed_by_file)} lockfile(s). {reverted_files} lockfile(s) reverted.")
434443
return 0
435444

436445

446+
# instrumentation lockfiles live under these prefixes and ship in a separate PR from core modules.
447+
# Keep in sync with the file split in .github/workflows/update-gradle-dependencies.yaml
448+
INSTRUMENTATION_PATH_PREFIXES = ("dd-smoke-tests/", "dd-java-agent/instrumentation/")
449+
450+
451+
# classify a lockfile path as belonging to the instrumentation PR (vs the core modules PR)
452+
def is_instrumentation_path(relative_path: str) -> bool:
453+
normalized = relative_path.replace(os.sep, "/")
454+
return normalized.startswith(INSTRUMENTATION_PATH_PREFIXES)
455+
456+
437457
# build summary of reverted/downgraded dependencies for PR descriptions
458+
# path_filter restricts the summary to lockfiles whose relative path matches,
459+
# so each PR (core vs instrumentation) only lists the dependencies it actually changes
438460
def build_validation_summary(
439461
*,
440462
violations_by_file: dict[str, list[tuple[str, str, int]]],
441463
replacements_by_file: dict[str, dict[str, tuple[str, int]]],
442464
baseline_lockfiles: dict[str, set[str]],
443465
min_age_hours: int,
466+
path_filter: Callable[[str], bool],
444467
) -> str:
445-
if not violations_by_file and not replacements_by_file:
446-
return ""
447-
lines = [f"## Dependency age policy", ""]
468+
header = ["## Dependency age policy", ""]
469+
lines = list(header)
448470
seen: set[str] = set()
449471
for relative_path, replacements in replacements_by_file.items():
472+
if not path_filter(relative_path):
473+
continue
450474
baseline_coords = baseline_lockfiles.get(relative_path, set())
451475
for old_gav, (new_gav, hours_remaining) in replacements.items():
452476
if old_gav not in seen:
@@ -456,14 +480,18 @@ def build_validation_summary(
456480
else:
457481
new_version = new_gav.rsplit(":", 1)[1]
458482
lines.append(f"- `{old_gav}` is {hours_remaining}h away from meeting {min_age_hours}h cooldown, updated to `{new_version}`")
459-
for entries in violations_by_file.values():
483+
for relative_path, entries in violations_by_file.items():
484+
if not path_filter(relative_path):
485+
continue
460486
for gav, kind, hours_remaining in entries:
461487
if gav not in seen:
462488
seen.add(gav)
463489
if kind == "unverified":
464490
lines.append(f"- `{gav}` — cannot verify age, reverted")
465491
else:
466492
lines.append(f"- `{gav}` is {hours_remaining}h away from meeting {min_age_hours}h cooldown, reverted")
493+
if len(lines) == len(header): # nothing matched the filter
494+
return ""
467495
return "\n".join(lines)
468496

469497

.github/scripts/tests/test_dependency_age.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
import re
44
import shutil
55
import subprocess
6+
import sys
67
import tempfile
78
import unittest
89
from pathlib import Path
910

10-
1111
REPO_ROOT = Path(__file__).resolve().parents[3]
1212
SCRIPT = REPO_ROOT / ".github/scripts/dependency_age.py"
13+
14+
# dependency_age.py is a loose script (not a package); add its dir to sys.path
15+
# so its helpers can be imported and unit-tested.
16+
sys.path.insert(0, str(SCRIPT.parent))
17+
import dependency_age
18+
19+
1320
FIXTURES = Path(__file__).resolve().parent / "fixtures"
1421
NOW = "2026-04-24T12:00:00Z"
1522
OUTPUT_PATTERN = re.compile(
@@ -373,6 +380,50 @@ def test_reverts_lockfile_when_metadata_override_has_invalid_timestamp(self) ->
373380
self.assertEqual(outputs["reverted_files"], "1")
374381
self.assertEqual((current_dir / "module/gradle.lockfile").read_text(encoding="utf-8"), baseline_content)
375382

383+
def test_is_instrumentation_path_classifies_prefixes(self) -> None:
384+
self.assertTrue(dependency_age.is_instrumentation_path("dd-smoke-tests/foo/gradle.lockfile"))
385+
self.assertTrue(dependency_age.is_instrumentation_path("dd-java-agent/instrumentation/bar/gradle.lockfile"))
386+
# core modules are not instrumentation
387+
self.assertFalse(dependency_age.is_instrumentation_path("dd-trace-core/gradle.lockfile"))
388+
self.assertFalse(dependency_age.is_instrumentation_path("dd-java-agent/agent-bootstrap/gradle.lockfile"))
389+
# real sibling modules that share the "dd-java-agent/instrumentation" stem but are
390+
# NOT under the "dd-java-agent/instrumentation/" prefix — the trailing slash excludes them
391+
self.assertFalse(dependency_age.is_instrumentation_path("dd-java-agent/instrumentation-testing/gradle.lockfile"))
392+
self.assertFalse(dependency_age.is_instrumentation_path("dd-java-agent/instrumentation-annotation-processor/gradle.lockfile"))
393+
394+
def _summary(self, *, path_filter) -> str:
395+
# one too-new violation in a core module, one in an instrumentation module
396+
return dependency_age.build_validation_summary(
397+
violations_by_file={
398+
"dd-trace-core/gradle.lockfile": [("com.example:core-lib:2.0.0", "too_new", 5)],
399+
"dd-java-agent/instrumentation/foo/gradle.lockfile": [("com.example:inst-lib:3.0.0", "too_new", 7)],
400+
},
401+
replacements_by_file={},
402+
baseline_lockfiles={},
403+
min_age_hours=48,
404+
path_filter=path_filter,
405+
)
406+
407+
def test_core_summary_excludes_instrumentation_entries(self) -> None:
408+
summary = self._summary(path_filter=lambda p: not dependency_age.is_instrumentation_path(p))
409+
self.assertIn("com.example:core-lib:2.0.0", summary)
410+
self.assertNotIn("com.example:inst-lib:3.0.0", summary)
411+
412+
def test_instrumentation_summary_excludes_core_entries(self) -> None:
413+
summary = self._summary(path_filter=dependency_age.is_instrumentation_path)
414+
self.assertIn("com.example:inst-lib:3.0.0", summary)
415+
self.assertNotIn("com.example:core-lib:2.0.0", summary)
416+
417+
def test_summary_is_empty_when_filter_matches_nothing(self) -> None:
418+
empty = dependency_age.build_validation_summary(
419+
violations_by_file={"dd-trace-core/gradle.lockfile": [("com.example:core-lib:2.0.0", "too_new", 5)]},
420+
replacements_by_file={},
421+
baseline_lockfiles={},
422+
min_age_hours=48,
423+
path_filter=dependency_age.is_instrumentation_path, # nothing under instrumentation
424+
)
425+
self.assertEqual(empty, "")
426+
376427

377428
if __name__ == "__main__":
378429
unittest.main()

.github/workflows/add-release-to-cloudfoundry.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- name: Checkout "cloudfoundry" branch
13-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
13+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
1414
with:
1515
ref: cloudfoundry
1616
- name: Get release version

.github/workflows/analyze-changes.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
steps:
1818
- name: Checkout repository
19-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
19+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
2020
with:
2121
submodules: 'recursive'
2222
- name: Cache Gradle dependencies
@@ -30,7 +30,7 @@ jobs:
3030
${{ runner.os }}-gradle-
3131
3232
- name: Initialize CodeQL
33-
uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
33+
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
3434
with:
3535
languages: 'java'
3636
build-mode: 'manual'
@@ -43,7 +43,7 @@ jobs:
4343
./gradlew clean :dd-java-agent:shadowJar --build-cache --parallel --stacktrace --no-daemon --max-workers=4
4444
4545
- name: Perform CodeQL Analysis and upload results to GitHub Security tab
46-
uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
46+
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
4747

4848
trivy:
4949
name: Analyze changes with Trivy
@@ -55,7 +55,7 @@ jobs:
5555

5656
steps:
5757
- name: Checkout repository
58-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
58+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
5959
with:
6060
submodules: 'recursive'
6161

@@ -102,13 +102,13 @@ jobs:
102102
TRIVY_JAVA_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-java-db,public.ecr.aws/aquasecurity/trivy-java-db
103103

104104
- name: Upload Trivy scan results to GitHub Security tab
105-
uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
105+
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
106106
if: always()
107107
with:
108108
sarif_file: 'trivy-results.sarif'
109109

110110
- name: Install datadog-ci
111-
uses: DataDog/install-datadog-ci-github-action@6d7f0c7c5402a4b1912055b76970ca76bef71fe5 # v1.0.4
111+
uses: DataDog/install-datadog-ci-github-action@501e9d922bf506902d2ecc2c830b0f4471760396 # v1.0.6
112112
with:
113113
version: v5.17.0
114114
- name: Upload results to Datadog CI Static Analysis

.github/workflows/create-release-branch.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
echo "branch=release/${TAG%.0}.x" >> "$GITHUB_OUTPUT"
4141
4242
- name: Check out repo at tag
43-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
43+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
4444
with:
4545
ref: ${{ steps.determine-tag.outputs.tag }}
4646

@@ -76,7 +76,7 @@ jobs:
7676
policy: self.pin-system-tests.create-pr
7777

7878
- name: Check out repo at release branch
79-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
79+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
8080
with:
8181
ref: ${{ needs.create-release-branch.outputs.release-branch-name }}
8282

.github/workflows/run-system-tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
group: APM Larger Runners
2525
steps:
2626
- name: Checkout repository
27-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
27+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # 6.0.3
2828
with:
2929
submodules: 'recursive'
3030
fetch-depth: 0

0 commit comments

Comments
 (0)