Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6993dc3
refactor(llmobs): centralize experiments API client (#9622)
mehulsonowal Aug 7, 2026
7a556e5
fix(opentelemetry): use Unix timestamps for OTLP logs (#9619)
wconti27 Aug 7, 2026
9bd1d30
refactor(llmobs): expose dataset fields (#9719)
mehulsonowal Aug 7, 2026
feeb0d5
fix(llmobs): add per-integration opt-out (#9733)
crysmags Aug 7, 2026
beeec55
chore(deps): bump the test-versions group across 1 directory with 2 u…
dependabot[bot] Aug 10, 2026
074b326
chore(deps): bump the testing-and-build group across 1 directory with…
dependabot[bot] Aug 10, 2026
d47753f
chore(deps): bump the ai-and-llm group across 1 directory with 16 upd…
dependabot[bot] Aug 10, 2026
8863e51
test(test-optimization): avoid Playwright payload timeout race (#9751)
juan-fernandez Aug 10, 2026
1a15637
fix(mariadb): support versions 3.5.1 and 3.5.2 (#9734)
crysmags Aug 10, 2026
d14a603
fix(iast): compile module body exactly once in rewriter _compile hook…
IlyasShabi Aug 10, 2026
56ee155
test(appsec): avoid shell execution in taint tracking tests (#9657)
BridgeAR Aug 10, 2026
b0e3617
feat(serverless): tag Vercel runtime spans (#9660)
wconti27 Aug 10, 2026
6b91310
chore(openfeature): expand CODEOWNERS coverage (#9689)
leoromanovsky Aug 10, 2026
22df013
chore(eslint): update eslint-plugin-n and callback names (#9694)
BridgeAR Aug 10, 2026
139b47f
chore(codeowners): cover existing ownership gaps (#9635)
BridgeAR Aug 10, 2026
f790076
ci(release): credit contributors and correct changelog context (#9631)
BridgeAR Aug 10, 2026
0b479ac
test(appsec): expect Fastify QUERY endpoints (#9755)
BridgeAR Aug 10, 2026
e9f7618
chore(deps): bump @happy-dom/jest-environment (#9758)
dependabot[bot] Aug 11, 2026
3cf41a6
chore(deps): bump the ai-and-llm group across 1 directory with 6 upda…
dependabot[bot] Aug 11, 2026
31da931
test(appsec): avoid shell execution in command injection sink tests (…
IlyasShabi Aug 11, 2026
24891fd
fix(loader): avoid Node 20.0 loader recursion (#9632)
BridgeAR Aug 11, 2026
7647651
perf(serverless): optimize Vercel platform tags (#9776)
wconti27 Aug 11, 2026
03ae4de
fix(http): allow W3C tracing headers in CORS preflight (#9779)
pabloerhard Aug 11, 2026
2ae3c3c
ci: update one-pipeline to 1.3.0 (#9778)
gh-worker-campaigns-3e9aa4[bot] Aug 11, 2026
fb54e74
chore(deps): bump the test-versions group across 1 directory with 3 u…
dependabot[bot] Aug 12, 2026
48c7f3f
chore(deps): bump esbuild (#9783)
dependabot[bot] Aug 12, 2026
2224e2b
chore(deps): bump the databases group across 1 directory with 18 upda…
dependabot[bot] Aug 12, 2026
1a826d9
chore(deps): bump the gh-actions-packages group across 2 directories …
dependabot[bot] Aug 12, 2026
af62fde
chore(deps): bump the web-frameworks group across 1 directory with 7 …
dependabot[bot] Aug 12, 2026
4de27f5
feat(aiguard): evaluating anthropic calls with AI guard automatically…
IlyasShabi Aug 12, 2026
d4fc253
chore(profiling): Update profiler to 5.18.0 (#9791)
szegedi Aug 12, 2026
19483d2
fix(test-optimization): parse rate-limit reset delays (#9788)
juan-fernandez Aug 12, 2026
3f259ee
fix(datastreams): reset edge start per hop so edge latency is not cum…
rkaneriya Aug 12, 2026
90a8925
test(couchbase): wait for a usable KV connection (#9792)
BridgeAR Aug 12, 2026
2649e14
fix(test-optimization): bound final flush lifecycle (#9789)
juan-fernandez Aug 12, 2026
cc9f9d1
chore(deps): bump pnpm (#9800)
dependabot[bot] Aug 13, 2026
324b6cd
fix(electron): gate the Electron plugin behind an experimental flag (…
rochdev Aug 13, 2026
e570f76
feat(openfeature): vendor the flagging provider instead of an optiona…
rochdev Aug 13, 2026
bf8daab
fix(test-optimization): preserve deferred test session traces (#9790)
juan-fernandez Aug 13, 2026
e937cbf
refactor(aiguard): slim down sdk file (#9753)
IlyasShabi Aug 13, 2026
3b70f56
fix(debugger): reuse loaded tracer for trace context in devtools clie…
watson Aug 13, 2026
4771c65
feat(otel-thread-ctx): Node.js OTEP-4947 thread-context writer (#9210)
szegedi Aug 13, 2026
4b9e9c9
fix(playwright): preserve reporter finalization errors (#9796)
juan-fernandez Aug 13, 2026
4378685
fix(cypress): preserve lifecycle finalization errors (#9797)
juan-fernandez Aug 13, 2026
f8a65d4
test(bullmq): support version 6 (#9651)
BridgeAR Aug 13, 2026
9f5b483
chore(deps): bump the cloud-and-messaging group across 1 directory wi…
dependabot[bot] Aug 13, 2026
09b65e3
feat(llmobs): add external experiment recorder (#9623)
mehulsonowal Aug 13, 2026
b253ce9
fix(llmobs): align no-op external span types (#9799)
mehulsonowal Aug 13, 2026
e72120a
ci: update one-pipeline to 1.3.1 (#9806)
gh-worker-campaigns-3e9aa4[bot] Aug 13, 2026
af7c646
test: fail empty plugin and instrumentation suites (#9772)
BridgeAR Aug 13, 2026
7564b94
fix(cypress): finalize interactive test sessions (#9807)
juan-fernandez Aug 13, 2026
6c2ba69
bench(appsec): make benchmark workloads deterministic (#9804)
BridgeAR Aug 13, 2026
1961d35
test(aws-sdk): decouple Kinesis size-gate test from LocalStack (#9770)
BridgeAR Aug 13, 2026
54799ab
chore(eslint): block process.env rule bypasses (#9679)
bm1549 Aug 13, 2026
ef2300c
feat(mariadb): trace pool connection acquisition (#8923)
BridgeAR Aug 13, 2026
632a6d5
refactor(llmobs): track dataset changes locally (#9809)
mehulsonowal Aug 13, 2026
9958012
chore(deps): bump the ai-and-llm group across 1 directory with 5 upda…
dependabot[bot] Aug 14, 2026
db21dfa
chore(deps): bump the cloud-and-messaging group across 1 directory wi…
dependabot[bot] Aug 14, 2026
3281e56
chore(deps): bump the testing-and-build group across 1 directory with…
dependabot[bot] Aug 14, 2026
9e13853
chore(deps): bump the databases group across 1 directory with 2 updat…
dependabot[bot] Aug 14, 2026
e06ef77
v6.11.0
BridgeAR Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
130 changes: 110 additions & 20 deletions .github/CODEOWNERS

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .github/workflows/apm-integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ jobs:
PLUGINS: aerospike
SERVICES: aerospike
PACKAGE_VERSION_RANGE: ${{ matrix.range }}
DD_INJECT_FORCE: "true"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ./.github/actions/node
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:

- name: Initialize CodeQL
id: init-codeql
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
languages: ${{ matrix.language }}
config-file: .github/codeql_config.yml
Expand All @@ -57,7 +57,7 @@ jobs:

- name: Perform CodeQL Analysis
id: analyze
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
token: ${{ github.token }}
wait-for-processing: false
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/instrumentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ./.github/actions/instrumentations/test

instrumentation-anthropic-lifecycle:
runs-on: ubuntu-latest
permissions:
id-token: write
env:
PLUGINS: anthropic|anthropic-lifecycle
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ./.github/actions/instrumentations/test

instrumentation-aws-sdk:
runs-on: ubuntu-latest
permissions:
Expand Down
48 changes: 34 additions & 14 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Pull Request Title

on:
pull_request_target:
types: [opened, edited, reopened]
types: [opened, edited, reopened, synchronize]
branches:
- "master"

Expand All @@ -14,13 +14,20 @@ jobs:
conventional-commit:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
env:
# Shared between both steps. Must stay portable across bash ERE and JS
# regex (no lookarounds, named groups, or other JS-only features).
# Revert PRs always get semver-patch regardless of the original change's type.
PR_TITLE_PATTERN: '^(revert(!)?: .+|(feat|fix|docs|style|refactor|perf|test|bench|build|ci|chore)(\(([^)]+)\))?(!)?: .+)'
steps:
- name: Checkout base revision
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false

- name: Auto-rename GitHub revert title to Conventional Commit
id: rename
if: startsWith(github.event.pull_request.title, 'Revert "')
Expand All @@ -39,22 +46,35 @@ jobs:
})
core.setOutput('renamed', 'true')

- name: Validate PR title against Conventional Commits
- name: Validate PR title and release-note context
if: >-
steps.rename.outputs.renamed != 'true' &&
(github.event.action != 'edited' || github.event.changes.title != null)
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
if [[ ! "$PR_TITLE" =~ $PR_TITLE_PATTERN ]]; then
echo "::error::PR title does not follow Conventional Commits format."
echo "Got: $PR_TITLE"
echo "Expected: <type>(<scope>)?(!)?: <subject>"
echo " revert(!)?: <subject> (for reverts, always semver-patch)"
echo "Allowed types: feat, fix, docs, style, refactor, perf, test, bench, build, ci, chore"
exit 1
fi
echo "PR title OK: $PR_TITLE"
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const pullRequest = context.payload.pull_request
const title = pullRequest.title || ''
const match = title.match(new RegExp(process.env.PR_TITLE_PATTERN))
if (!match) {
core.setFailed('PR title does not follow Conventional Commits format.')
return
}
core.info(`PR title OK: ${title}`)

const type = match[3]
const changedFiles = await github.paginate(github.rest.pulls.listFiles, {
...context.repo,
pull_number: pullRequest.number,
per_page: 100,
})
const files = []
const { appendChangedPaths, isInternalOnly } = require('./scripts/release/changelog')
appendChangedPaths(files, changedFiles)
if (/^(?:feat|fix|perf|docs)$/.test(type) && isInternalOnly(files)) {
core.setFailed(`PR title type "${type}" is public, but every changed file is internal. ` +
'Use test, bench, ci, or chore.')
}

- name: Sync labels with PR title
if: steps.rename.outputs.renamed != 'true'
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/profiling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- uses: ./.github/actions/install
- run: npm run test:profiler:ci
- run: npm run test:integration:profiler:coverage
- run: npm run test:otel-thread-ctx
- uses: ./.github/actions/coverage
with:
flags: profiling-macos
Expand Down Expand Up @@ -60,6 +61,7 @@ jobs:
- uses: ./.github/actions/node/latest
- run: npm run test:profiler:ci
- run: npm run test:integration:profiler:coverage
- run: npm run test:otel-thread-ctx
- uses: ./.github/actions/coverage
with:
flags: profiling-ubuntu
Expand Down Expand Up @@ -118,6 +120,7 @@ jobs:
) | ForEach-Object { "$_=" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 }
- run: npm run test:profiler:ci
- run: npm run test:integration:profiler:coverage
- run: npm run test:otel-thread-ctx
- uses: ./.github/actions/node-crash-report
if: failure()
# Upload any WER minidumps that landed during this job, even on
Expand Down
2 changes: 1 addition & 1 deletion .gitlab/one-pipeline.locked.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# DO NOT EDIT THIS FILE MANUALLY
# This file is auto-generated by automation.
include:
- remote: https://gitlab-templates.ddbuild.io/libdatadog/include/versions/1.2.0/one-pipeline.yml
- remote: https://gitlab-templates.ddbuild.io/libdatadog/include/versions/1.3.1/one-pipeline.yml
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,23 +93,6 @@ Regardless of where you open the issue, someone at Datadog will try to help.

If you would like to trace your bundled application then please read this page on [bundling and dd-trace](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/nodejs/#bundling). It includes information on how to use our ESBuild plugin and includes caveats for other bundlers.

When using the experimental OpenFeature provider, file-traced deployments can force the optional provider and
its dependencies into the output with a side-effect import before accessing `tracer.openfeature`:

CommonJS:

```js
require('dd-trace/openfeature')
```

ES modules:

```js
import 'dd-trace/openfeature.js'
```

This is a fallback for build tools that do not recognize the provider's optional-require wrapper.


## Security Vulnerabilities

Expand Down
7 changes: 3 additions & 4 deletions benchmark/sirun/appsec-iast/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
Drives real Express request handling with the tracer loaded, measuring IAST's
per-request taint-tracking overhead -- IAST off vs on (default sampling, and
always-active), across a non-vulnerable endpoint and one with a command-injection
sink that triggers vulnerability reporting.
Drives real Express request handling with the tracer loaded, measuring default
IAST per-request taint-tracking across a non-vulnerable endpoint and one with a
command-injection sink.
23 changes: 4 additions & 19 deletions benchmark/sirun/appsec-iast/client.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
'use strict'

const http = require('http')
const { port, reqs } = require('./common')

let connectionsMade = 0
function request (opts) {
http.get(opts, (res) => {
res.on('data', () => {})
res.on('end', () => {
if (++connectionsMade !== reqs) {
request(opts)
}
})
}).on('error', (e) => {
setTimeout(() => {
request(opts)
}, 10)
})
}
const runRequests = require('../http-client')
const { port, reqs, warmup } = require('./common')

const path = '/?param=value'
const opts = {
headers: {
accept: 'text/html',
},
host: '127.0.0.1',
port,
path,
}
request(opts)
runRequests(opts, warmup, reqs, 1)
7 changes: 2 additions & 5 deletions benchmark/sirun/appsec-iast/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

module.exports = {
port: 3331 + parseInt(process.env.CPU_AFFINITY || '0', 10),
// Env-tunable like the other live benches. Local tuning (keep-alive, higher
// counts) did not reduce the run-to-run jitter -- it is express/IAST scheduling
// noise that CI core-pinning addresses, not connection churn -- so this is left
// at a modest default and gated on CI.
reqs: Number(process.env.REQS) || 100,
reqs: Number(process.env.OPERATIONS) || 100,
warmup: 100,
}
66 changes: 17 additions & 49 deletions benchmark/sirun/appsec-iast/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,39 @@
"instructions": true,
"iterations": 15,
"variants": {
"no-vulnerability-control": {
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-without-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-without-vulnerability.js\"",
"env": {
"DD_IAST_ENABLED": "0"
}
},
"no-vulnerability-iast-enabled-default-config": {
"cpus": 2,
"iterations": 5,
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-without-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-without-vulnerability.js\"",
"env": {
"DD_IAST_ENABLED": "1"
}
},
"no-vulnerability-iast-enabled-always-active": {
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-without-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-without-vulnerability.js\"",
"setup_with_affinity": "bash -c \"nohup taskset -c $CPU_AFFINITY_SECOND node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../startup-guard.js --require ../noop-request.js --require ../../../init.js server-without-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../startup-guard.js --require ../noop-request.js --require ../../../init.js server-without-vulnerability.js\"",
"env": {
"DD_INJECT_FORCE": "true",
"DD_IAST_ENABLED": "1",
"DD_IAST_REQUEST_SAMPLING": "100",
"DD_IAST_MAX_CONCURRENT_REQUESTS": "1000",
"DD_IAST_MAX_CONTEXT_OPERATIONS": "100"
}
},
"with-vulnerability-control": {
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-with-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-with-vulnerability.js\"",
"env": {
"DD_IAST_ENABLED": "0"
"DD_REMOTE_CONFIGURATION_ENABLED": "false",
"OPERATIONS": "30000"
}
},
"with-vulnerability-iast-enabled-default-config": {
"cpus": 2,
"iterations": 5,
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-with-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-with-vulnerability.js\"",
"env": {
"DD_IAST_ENABLED": "1"
}
},
"with-vulnerability-iast-enabled-always-active": {
"setup": "bash -c \"nohup node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../../../init.js server-with-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js server-with-vulnerability.js\"",
"setup_with_affinity": "bash -c \"nohup taskset -c $CPU_AFFINITY_SECOND node client.js >/dev/null 2>&1 &\"",
"run": "node --require ../startup-guard.js --require ../noop-request.js --require ../../../init.js server-with-vulnerability.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../startup-guard.js --require ../noop-request.js --require ../../../init.js server-with-vulnerability.js\"",
"env": {
"DD_INJECT_FORCE": "true",
"DD_IAST_ENABLED": "1",
"DD_IAST_REQUEST_SAMPLING": "100",
"DD_IAST_MAX_CONCURRENT_REQUESTS": "1000",
"DD_IAST_MAX_CONTEXT_OPERATIONS": "100"
}
},
"startup-time-control": {
"run": "node --require ../../../init.js insecure-bank.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js insecure-bank.js\"",
"env": {
"DD_IAST_ENABLED": "0"
"DD_REMOTE_CONFIGURATION_ENABLED": "false",
"OPERATIONS": "11500"
}
},
"startup-time-iast-enabled": {
"run": "node --require ../../../init.js insecure-bank.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node --require ../../../init.js insecure-bank.js\"",
"env": {
"DD_INJECT_FORCE": "true",
"DD_IAST_ENABLED": "1"
}
}
Expand Down
27 changes: 27 additions & 0 deletions benchmark/sirun/appsec-iast/noop-child-process.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict'

/**
* @param {typeof import('node:child_process').ChildProcess} ChildProcess
*/
module.exports = function installNoopSpawn (ChildProcess) {
/**
* @param {{ file: string, args?: string[] }} options
*/
ChildProcess.prototype.spawn = function noopSpawn (options) {
this.spawnfile = options.file
this.spawnargs = options.args ?? []
this.pid = 1
this.stdin = null
this.stdout = null
this.stderr = null
this.stdio = [null, null, null]

process.nextTick(() => {
this.emit('spawn')
this.emit('exit', 0, null)
this.emit('close', 0, null)
})

return 0
}
}
30 changes: 9 additions & 21 deletions benchmark/sirun/appsec-iast/server-with-vulnerability.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
'use strict'

const assert = require('node:assert/strict')
const childProcess = require('child_process')
const express = require('../../../versions/express').get()
const cookieParser = require('../../../versions/cookie-parser').get()
const { port, reqs } = require('./common')
const childProcess = require('node:child_process')

const app = express()
app.use(cookieParser())
require('./noop-child-process')(childProcess.ChildProcess)

let connectionsMade = 0
/**
* @param {import('express').Request} req
*/
function runSink (req) {
childProcess.exec(req.query.param, noop)
}

function noop () {}

app.get('/', (req, res) => {
childProcess.exec('echo #' + req.query.param, noop)
res.writeHead(200)
res.end('Hello, World!')

if (++connectionsMade === reqs) {
server.close()
}
})

const server = app.listen(port, () => {
assert.ok(server.address(), 'appsec-iast server failed to bind')
})
require('./server')(runSink, 'COMMAND_INJECTION')
Loading
Loading