Skip to content

Commit e8ef083

Browse files
authored
Merge branch 'master' into ishabi/anthropic-aiguard
2 parents 5bf825e + fdd7d8b commit e8ef083

150 files changed

Lines changed: 6955 additions & 976 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.

.github/workflows/codeql-analysis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545

4646
- name: Initialize CodeQL
4747
id: init-codeql
48-
uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
48+
uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
4949
with:
5050
languages: ${{ matrix.language }}
5151
config-file: .github/codeql_config.yml
@@ -57,7 +57,7 @@ jobs:
5757

5858
- name: Perform CodeQL Analysis
5959
id: analyze
60-
uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
60+
uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
6161
with:
6262
token: ${{ github.token }}
6363
wait-for-processing: false

.github/workflows/llmobs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ jobs:
311311
env:
312312
PLUGINS: openai-agents
313313
steps:
314-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
314+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
315315
- uses: ./.github/actions/testagent/start
316316
- uses: ./.github/actions/node/oldest-maintenance-lts
317317
- uses: ./.github/actions/install

.github/workflows/mirror-image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
policy: self.mirror-image
2929

3030
- name: Log in to GHCR
31-
uses: docker/login-action@v4
31+
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
3232
with:
3333
registry: ghcr.io
3434
username: ${{ github.actor }}

.github/workflows/test-optimization.yml

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ jobs:
5656
- name: Get Playwright version from versions package.json
5757
id: playwright-version
5858
run: |
59-
PLAYWRIGHT_VERSION=$(node -p "require('./packages/dd-trace/test/plugins/versions/package.json').dependencies['@playwright/test']")
59+
PLAYWRIGHT_VERSION=$(node -p \
60+
"const versions = require('./integration-tests/playwright/versions'); \
61+
versions.getLatestPlaywrightSpecifier() === 'latest' \
62+
? versions.latest \
63+
: versions.latestSupportedByNode18")
6064
echo "version=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT
6165
echo "Playwright version: $PLAYWRIGHT_VERSION"
6266
- name: Cache Playwright browsers
@@ -73,14 +77,14 @@ jobs:
7377
strategy:
7478
fail-fast: false
7579
matrix:
76-
playwright-version: [oldest, latest]
80+
playwright-version: [oldest, latest, latest-node18]
7781
name: Ensure Playwright Docker image (${{ matrix.playwright-version }})
7882
runs-on: ubuntu-latest
7983
permissions:
8084
contents: read
8185
packages: write
8286
outputs:
83-
# Both matrix jobs set this to the same value, so the last-writer-wins
87+
# All matrix jobs set this to the same value, so the last-writer-wins
8488
# behaviour of matrix outputs is safe here.
8589
images: ${{ steps.versions.outputs.images }}
8690
steps:
@@ -89,19 +93,35 @@ jobs:
8993
id: versions
9094
run: |
9195
LATEST=$(node -p "require('./integration-tests/playwright/versions').latest")
96+
LATEST_NODE18=$(node -p "require('./integration-tests/playwright/versions').latestSupportedByNode18")
9297
OLDEST=$(node -p "require('./integration-tests/playwright/versions').oldest")
9398
DOCKER_HASH=$(sha256sum .github/playwright/Dockerfile | cut -c1-8)
9499
LATEST_TAG="${LATEST}-${DOCKER_HASH}"
100+
LATEST_NODE18_TAG="${LATEST_NODE18}-${DOCKER_HASH}"
95101
OLDEST_TAG="${OLDEST}-${DOCKER_HASH}"
96102
BASE="ghcr.io/datadog/dd-trace-js/playwright-tools"
97-
IMAGES=$(printf '{"latest":"%s:%s","oldest":"%s:%s"}' "$BASE" "$LATEST_TAG" "$BASE" "$OLDEST_TAG")
98-
PW_VERSION=$([ "${{ matrix.playwright-version }}" = "latest" ] && echo "$LATEST" || echo "$OLDEST")
99-
IMAGE_TAG=$([ "${{ matrix.playwright-version }}" = "latest" ] && echo "$LATEST_TAG" || echo "$OLDEST_TAG")
103+
IMAGES=$(printf \
104+
'{"latest":{"latest":"%s:%s","oldest":"%s:%s"},"oldest":{"latest":"%s:%s","oldest":"%s:%s"}}' \
105+
"$BASE" "$LATEST_TAG" "$BASE" "$OLDEST_TAG" "$BASE" "$LATEST_NODE18_TAG" "$BASE" "$OLDEST_TAG")
106+
case "${{ matrix.playwright-version }}" in
107+
latest)
108+
PW_VERSION="$LATEST"
109+
IMAGE_TAG="$LATEST_TAG"
110+
;;
111+
latest-node18)
112+
PW_VERSION="$LATEST_NODE18"
113+
IMAGE_TAG="$LATEST_NODE18_TAG"
114+
;;
115+
*)
116+
PW_VERSION="$OLDEST"
117+
IMAGE_TAG="$OLDEST_TAG"
118+
;;
119+
esac
100120
echo "images=$IMAGES" >> $GITHUB_OUTPUT
101121
echo "pw-version=$PW_VERSION" >> $GITHUB_OUTPUT
102122
echo "image-tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
103123
- name: Log in to GHCR
104-
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
124+
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
105125
with:
106126
registry: ghcr.io
107127
username: ${{ github.actor }}
@@ -140,7 +160,7 @@ jobs:
140160
permissions:
141161
id-token: write
142162
container:
143-
image: ${{ fromJson(needs.playwright-image.outputs.images)[matrix.playwright-version] }}
163+
image: ${{ fromJson(needs.playwright-image.outputs.images)[matrix.node-version][matrix.playwright-version] }}
144164
credentials:
145165
username: ${{ github.actor }}
146166
password: ${{ secrets.GITHUB_TOKEN }}
@@ -214,12 +234,12 @@ jobs:
214234
name: integration-webdriverio (${{ matrix.webdriverio-version }}, node-${{ matrix.node-version }})
215235
runs-on: ubuntu-latest
216236
steps:
217-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
237+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
218238
- uses: ./.github/actions/node
219239
with:
220240
version: ${{ matrix.node-version }}
221241
- uses: ./.github/actions/install
222-
- run: npm run test:instrumentations
242+
- run: npm run test:instrumentations:ci
223243
env:
224244
PLUGINS: webdriverio
225245
- run: npm run test:integration:webdriverio:coverage
@@ -279,6 +299,14 @@ jobs:
279299
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
280300
- uses: ./.github/actions/plugins/test
281301

302+
dependency-helpers:
303+
runs-on: ubuntu-latest
304+
steps:
305+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
306+
- uses: ./.github/actions/node
307+
- uses: ./.github/actions/install
308+
- run: npm run test:integration:test-optimization:helpers
309+
282310
integration-cucumber:
283311
strategy:
284312
fail-fast: false
@@ -326,7 +354,7 @@ jobs:
326354
IMAGE="ghcr.io/datadog/dd-trace-js/selenium-tools:${DOCKER_HASH}"
327355
echo "image=$IMAGE" >> $GITHUB_OUTPUT
328356
- name: Log in to GHCR
329-
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
357+
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
330358
with:
331359
registry: ghcr.io
332360
username: ${{ github.actor }}
@@ -499,3 +527,45 @@ jobs:
499527
- uses: ./.github/actions/coverage
500528
with:
501529
flags: test-optimization-vitest-${{ matrix.version }}
530+
531+
integration-vitest-browser:
532+
needs: playwright-image
533+
runs-on: ubuntu-latest
534+
permissions:
535+
id-token: write
536+
strategy:
537+
fail-fast: false
538+
matrix:
539+
version: [oldest, latest]
540+
name: integration-vitest-browser (node-${{ matrix.version }})
541+
container:
542+
image: ${{ fromJson(needs.playwright-image.outputs.images)[matrix.version].latest }}
543+
credentials:
544+
username: ${{ github.actor }}
545+
password: ${{ secrets.GITHUB_TOKEN }}
546+
env:
547+
DD_SERVICE: dd-trace-js-integration-tests
548+
DD_CIVISIBILITY_AGENTLESS_ENABLED: 1
549+
OPTIONS_OVERRIDE: 1
550+
steps:
551+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
552+
- uses: ./.github/actions/dd-sts-api-key
553+
id: dd-sts
554+
continue-on-error: true
555+
- uses: ./.github/actions/node
556+
with:
557+
version: ${{ matrix.version }}
558+
- uses: ./.github/actions/install
559+
- name: Configure Git safe directory
560+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
561+
- run: npm run test:instrumentations
562+
env:
563+
PLUGINS: vitest-main
564+
- run: npm run test:integration:vitest:coverage
565+
env:
566+
NODE_OPTIONS: "-r ./ci/init"
567+
DD_API_KEY: ${{ steps.dd-sts.outputs.api_key }}
568+
SPEC: vitest.browser
569+
- uses: ./.github/actions/coverage
570+
with:
571+
flags: test-optimization-vitest-browser-${{ matrix.version }}

.github/workflows/update-3rdparty-licenses.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3333

3434
- name: Set up Python
35-
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
35+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
3636
with:
3737
python-version: "3.14"
3838

AGENTS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,19 @@ Composition is the default; inheritance only when ≤2 sibling types share a com
271271
- Don't use language/runtime features that are too new
272272
- **Guard breaking changes with version checks** using [`version.js`](./version.js) (e.g., `DD_MAJOR`)
273273

274+
#### The supported Node.js range differs per release line
275+
276+
`engines.node` is `>=22` on `master`, `>=18` on `v5.x`, so never hardcode a major in a runtime gate —
277+
derive it from `engines.node` + `nodeMaxMajor`, the source `src/guardrails/index.js` reads. Below the
278+
floor the guardrail aborts instrumentation entirely, yet CI still runs Node 18 and 20 on `master` so
279+
backports stay honest. A spec needing a live tracer must therefore skip outside the range, honouring
280+
`DD_INJECT_FORCE` as `withVersions` (`packages/dd-trace/test/setup/mocha.js`) does:
281+
282+
```js
283+
const runtimeSupported = Boolean(process.env.DD_INJECT_FORCE) ||
284+
semver.satisfies(process.version, `${engines.node} <${nodeMaxMajor}`)
285+
```
286+
274287
### Public TypeScript Types
275288

276289
The repo carries two public TypeScript surfaces:

ci/test-optimization-validation/command-output-policy.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,21 @@ function cleanupCommandOutputs (states) {
7171
*
7272
* @param {string} outputPath output path
7373
* @param {string} repositoryRoot repository root
74-
* @returns {{path: string, dev: number, ino: number}[]} parent identities
74+
* @returns {{path: string, dev: bigint, ino: bigint}[]} parent identities
7575
*/
7676
function captureExistingParentIdentities (outputPath, repositoryRoot) {
7777
const identities = []
7878
const relative = path.relative(repositoryRoot, path.dirname(outputPath))
7979
let current = repositoryRoot
8080
for (const segment of relative ? relative.split(path.sep) : []) {
81-
const stat = fs.lstatSync(current)
81+
const stat = fs.lstatSync(current, { bigint: true })
8282
assertRegularDirectory(stat, current)
8383
identities.push({ path: current, dev: stat.dev, ino: stat.ino })
8484
current = path.join(current, segment)
8585
if (!pathExists(current)) return identities
8686
}
8787

88-
const stat = fs.lstatSync(current)
88+
const stat = fs.lstatSync(current, { bigint: true })
8989
assertRegularDirectory(stat, current)
9090
identities.push({ path: current, dev: stat.dev, ino: stat.ino })
9191
return identities
@@ -98,7 +98,7 @@ function captureExistingParentIdentities (outputPath, repositoryRoot) {
9898
*/
9999
function assertOutputParentsUnchanged (state) {
100100
for (const identity of state.parentIdentities) {
101-
const stat = fs.lstatSync(identity.path)
101+
const stat = fs.lstatSync(identity.path, { bigint: true })
102102
assertRegularDirectory(stat, identity.path)
103103
if (stat.dev !== identity.dev || stat.ino !== identity.ino) {
104104
throw new Error(`Refusing command output cleanup because a parent directory changed: ${identity.path}`)
@@ -118,7 +118,7 @@ function assertOutputParentsUnchanged (state) {
118118
/**
119119
* Refuses symbolic links and non-directory parent components.
120120
*
121-
* @param {fs.Stats} stat path status
121+
* @param {fs.Stats | fs.BigIntStats} stat path status
122122
* @param {string} directory directory path
123123
*/
124124
function assertRegularDirectory (stat, directory) {

ci/test-optimization-validation/generated-files.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

3-
const fs = require('fs')
4-
const path = require('path')
3+
const fs = require('node:fs')
4+
const path = require('node:path')
55

66
const {
77
MAX_GENERATED_FILES,
@@ -251,7 +251,7 @@ function forgetWrittenGeneratedFiles (filenames) {
251251
function authorizePathForCleanup (root, filename) {
252252
const lexicalRoot = path.resolve(root)
253253
const physicalRoot = fs.realpathSync(lexicalRoot)
254-
const rootStat = fs.statSync(physicalRoot)
254+
const rootStat = fs.statSync(physicalRoot, { bigint: true })
255255
const authorization = {
256256
lexicalRoot,
257257
physicalRoot,
@@ -276,7 +276,7 @@ function pinCleanupParent (authorization, filename) {
276276
try {
277277
const physicalParent = fs.realpathSync(path.dirname(filename))
278278
if (!isPathInside(authorization.physicalRoot, physicalParent)) return
279-
const parentStat = fs.statSync(physicalParent)
279+
const parentStat = fs.statSync(physicalParent, { bigint: true })
280280
authorization.physicalParent = physicalParent
281281
authorization.parentDevice = parentStat.dev
282282
authorization.parentInode = parentStat.ino
@@ -285,7 +285,7 @@ function pinCleanupParent (authorization, filename) {
285285

286286
function pinCleanupTarget (authorization, filename) {
287287
try {
288-
const targetStat = fs.lstatSync(filename)
288+
const targetStat = fs.lstatSync(filename, { bigint: true })
289289
authorization.targetDevice = targetStat.dev
290290
authorization.targetInode = targetStat.ino
291291
} catch {}
@@ -294,22 +294,22 @@ function pinCleanupTarget (authorization, filename) {
294294
function isCleanupAuthorizationValid (filename, authorization) {
295295
try {
296296
const currentPhysicalRoot = fs.realpathSync(authorization.lexicalRoot)
297-
const rootStat = fs.statSync(currentPhysicalRoot)
297+
const rootStat = fs.statSync(currentPhysicalRoot, { bigint: true })
298298
if (currentPhysicalRoot !== authorization.physicalRoot ||
299299
rootStat.dev !== authorization.rootDevice || rootStat.ino !== authorization.rootInode) {
300300
return false
301301
}
302302

303303
if (authorization.physicalParent === undefined) return false
304304
const physicalParent = fs.realpathSync(path.dirname(filename))
305-
const parentStat = fs.statSync(physicalParent)
305+
const parentStat = fs.statSync(physicalParent, { bigint: true })
306306
if (physicalParent !== authorization.physicalParent ||
307307
parentStat.dev !== authorization.parentDevice || parentStat.ino !== authorization.parentInode) {
308308
return false
309309
}
310310

311311
if (authorization.targetDevice !== undefined) {
312-
const targetStat = fs.lstatSync(filename)
312+
const targetStat = fs.lstatSync(filename, { bigint: true })
313313
if (targetStat.dev !== authorization.targetDevice || targetStat.ino !== authorization.targetInode) {
314314
return false
315315
}

ci/test-optimization-validation/offline-output.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ function readOfflineOutput (outputRoot) {
5757
if (!exporterInitialized) return emptyOutput()
5858

5959
const state = {
60-
bytes: 0,
61-
completionBytes: 0,
60+
bytes: 0n,
61+
completionBytes: 0n,
6262
decodedEntries: 0,
6363
files: 0,
6464
}
@@ -150,7 +150,7 @@ function readPayloadFiles (payloadsRoot, kind, state, consume) {
150150
}
151151

152152
function readRegularFile (filename, individualLimit, state, completion) {
153-
const stat = fs.lstatSync(filename)
153+
const stat = fs.lstatSync(filename, { bigint: true })
154154
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink > 1) {
155155
throw new Error('Offline validation artifact must be a regular, unlinked file.')
156156
}
@@ -163,16 +163,16 @@ function readRegularFile (filename, individualLimit, state, completion) {
163163

164164
const file = fs.openSync(filename, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0))
165165
try {
166-
const opened = fs.fstatSync(file)
166+
const opened = fs.fstatSync(file, { bigint: true })
167167
if (!opened.isFile() || opened.nlink > 1 || opened.dev !== stat.dev || opened.ino !== stat.ino) {
168168
throw new Error('Offline validation artifact changed while it was opened.')
169169
}
170170
const buffer = fs.readFileSync(file)
171-
const completed = fs.fstatSync(file)
171+
const completed = fs.fstatSync(file, { bigint: true })
172172
if (completed.size !== opened.size || completed.mtimeMs !== opened.mtimeMs) {
173173
throw new Error('Offline validation artifact changed while it was read.')
174174
}
175-
state[totalKey] += buffer.length
175+
state[totalKey] += BigInt(buffer.length)
176176
return buffer
177177
} finally {
178178
fs.closeSync(file)

0 commit comments

Comments
 (0)