Skip to content

Commit 6b2d9fe

Browse files
authored
add include configuration to iitm loader hook (#6455)
1 parent a31bc8f commit 6b2d9fe

File tree

10 files changed

+107
-21
lines changed

10 files changed

+107
-21
lines changed

LICENSE-3rdparty.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require,@opentelemetry/resources,Apache license 2.0,Copyright OpenTelemetry Auth
1414
require,@isaacs/ttlcache,ISC,Copyright (c) 2022-2023 - Isaac Z. Schlueter and Contributors
1515
require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
1616
require,dc-polyfill,MIT,Copyright 2023 Datadog Inc.
17+
require,escape-string-regexp,MIT,Copyright Sindre Sorhus
1718
require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
1819
require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
1920
require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.

index.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2815,7 +2815,10 @@ declare namespace tracer {
28152815
redactionValuePattern?: string,
28162816

28172817
/**
2818-
* Allows to enable security controls.
2818+
* Allows to enable security controls. This option is not supported when
2819+
* using ESM.
2820+
* @deprecated Please use the DD_IAST_SECURITY_CONTROLS_CONFIGURATION
2821+
* environment variable instead.
28192822
*/
28202823
securityControlsConfiguration?: string,
28212824

integration-tests/startup.spec.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ execArgvs.forEach(({ execArgv, skip }) => {
3535
let sandbox
3636
let cwd
3737
let startupTestFile
38+
let unsupportedTestFile
3839

3940
before(async () => {
40-
sandbox = await createSandbox()
41+
sandbox = await createSandbox(['d3-format@3.1.0'])
4142
cwd = sandbox.folder
4243
startupTestFile = path.join(cwd, 'startup/index.js')
44+
unsupportedTestFile = path.join(cwd, 'startup/unsupported.js')
4345
})
4446

4547
after(async () => {
@@ -218,5 +220,14 @@ execArgvs.forEach(({ execArgv, skip }) => {
218220
})
219221
})
220222
})
223+
224+
context('with unsupported module', () => {
225+
it('skips the unsupported module', async () => {
226+
await spawnProc(unsupportedTestFile, {
227+
cwd,
228+
execArgv
229+
})
230+
})
231+
})
221232
})
222233
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict'
2+
3+
const assert = require('assert')
4+
5+
/* eslint-disable-next-line n/no-missing-import */
6+
import('d3-format').then(({ format }) => {
7+
const siFormat = format('.4~s')
8+
9+
// This is `1.2undefined` when unexpectedly patched by import-in-the-middle.
10+
assert.equal(siFormat(1200), '1.2k')
11+
})

loader-hook.mjs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,52 @@
1-
export * from 'import-in-the-middle/hook.mjs'
1+
import regexpEscape from 'escape-string-regexp'
2+
import * as iitm from 'import-in-the-middle/hook.mjs'
3+
import hooks from './packages/datadog-instrumentations/src/helpers/hooks.js'
4+
import configHelper from './packages/dd-trace/src/config-helper.js'
5+
6+
// For some reason `getEnvironmentVariable` is not otherwise available to ESM.
7+
const env = configHelper.getEnvironmentVariable
8+
9+
function initialize (data = {}) {
10+
data.include ??= []
11+
data.exclude ??= []
12+
13+
addInstrumentations(data)
14+
addSecurityControls(data)
15+
addExclusions(data)
16+
17+
return iitm.initialize(data)
18+
}
19+
20+
function addInstrumentations (data) {
21+
const instrumentations = Object.keys(hooks)
22+
23+
for (const moduleName of instrumentations) {
24+
data.include.push(new RegExp(`node_modules/${moduleName}/(?!node_modules).+`), moduleName)
25+
}
26+
}
27+
28+
function addSecurityControls (data) {
29+
const securityControls = (env('DD_IAST_SECURITY_CONTROLS_CONFIGURATION') || '')
30+
.split(';')
31+
.map(sc => sc.trim().split(':')[2])
32+
.filter(Boolean)
33+
.map(sc => sc.trim())
34+
35+
for (const subpath of securityControls) {
36+
data.include.push(new RegExp(regexpEscape(subpath)))
37+
}
38+
}
39+
40+
function addExclusions (data) {
41+
data.exclude.push(
42+
/middle/,
43+
/langsmith/,
44+
/openai\/_shims/,
45+
/openai\/resources\/chat\/completions\/messages/,
46+
/openai\/agents-core\/dist\/shims/,
47+
/@anthropic-ai\/sdk\/_shims/
48+
)
49+
}
50+
51+
export { initialize }
52+
export { load, getFormat, resolve, getSource } from 'import-in-the-middle/hook.mjs'

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
"@opentelemetry/resources": ">=1.0.0 <1.10.0",
137137
"crypto-randomuuid": "^1.0.0",
138138
"dc-polyfill": "^0.1.10",
139+
"escape-string-regexp": "^5.0.0",
139140
"ignore": "^7.0.5",
140141
"import-in-the-middle": "^1.14.2",
141142
"istanbul-lib-coverage": "^3.2.2",

packages/dd-trace/src/config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const { appendRules } = require('./payload-tagging/config')
1919
const { getEnvironmentVariable: getEnv, getEnvironmentVariables } = require('./config-helper')
2020
const defaults = require('./config_defaults')
2121
const path = require('path')
22+
const { DD_MAJOR } = require('../../../version')
2223

2324
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
2425

@@ -1032,7 +1033,9 @@ class Config {
10321033
opts['iast.requestSampling'] = iastRequestSampling
10331034
this.#optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
10341035
}
1035-
opts['iast.securityControlsConfiguration'] = options.iast?.securityControlsConfiguration
1036+
if (DD_MAJOR < 6) {
1037+
opts['iast.securityControlsConfiguration'] = options.iast?.securityControlsConfiguration
1038+
}
10361039
this.#setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
10371040
this.#setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
10381041
this.#setBoolean(opts, 'isCiVisibility', options.isCiVisibility)

packages/dd-trace/test/config.spec.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ require('./setup/core')
1515
const { GRPC_CLIENT_ERROR_STATUSES, GRPC_SERVER_ERROR_STATUSES } = require('../src/constants')
1616
const { getEnvironmentVariable, getEnvironmentVariables } = require('../src/config-helper')
1717
const { assertObjectContains } = require('../../../integration-tests/helpers')
18+
const { DD_MAJOR } = require('../../../version')
1819

1920
describe('Config', () => {
2021
let Config
@@ -1170,8 +1171,12 @@ describe('Config', () => {
11701171
expect(config).to.have.nested.property('iast.redactionNamePattern', 'REDACTION_NAME_PATTERN')
11711172
expect(config).to.have.nested.property('iast.redactionValuePattern', 'REDACTION_VALUE_PATTERN')
11721173
expect(config).to.have.nested.property('iast.requestSampling', 50)
1173-
expect(config).to.have.nested.property('iast.securityControlsConfiguration',
1174-
'SANITIZER:CODE_INJECTION:sanitizer.js:method')
1174+
if (DD_MAJOR < 6) {
1175+
expect(config).to.have.nested.property('iast.securityControlsConfiguration',
1176+
'SANITIZER:CODE_INJECTION:sanitizer.js:method')
1177+
} else {
1178+
expect(config).to.not.have.property('iast.securityControlsConfiguration')
1179+
}
11751180
expect(config).to.have.nested.property('iast.stackTrace.enabled', false)
11761181
expect(config).to.have.nested.property('iast.telemetryVerbosity', 'DEBUG')
11771182
expect(config).to.have.nested.property('llmobs.agentlessEnabled', true)
@@ -1259,7 +1264,7 @@ describe('Config', () => {
12591264
{ name: 'iast.redactionNamePattern', value: 'REDACTION_NAME_PATTERN', origin: 'code' },
12601265
{ name: 'iast.redactionValuePattern', value: 'REDACTION_VALUE_PATTERN', origin: 'code' },
12611266
{ name: 'iast.requestSampling', value: 50, origin: 'code' },
1262-
{
1267+
DD_MAJOR < 6 && {
12631268
name: 'iast.securityControlsConfiguration',
12641269
value: 'SANITIZER:CODE_INJECTION:sanitizer.js:method',
12651270
origin: 'code'
@@ -1289,7 +1294,7 @@ describe('Config', () => {
12891294
{ name: 'traceId128BitGenerationEnabled', value: true, origin: 'code' },
12901295
{ name: 'traceId128BitLoggingEnabled', value: true, origin: 'code' },
12911296
{ name: 'version', value: '0.1.0', origin: 'code' }
1292-
])
1297+
].filter(v => v))
12931298
})
12941299

12951300
it('should initialize from the options with url taking precedence', () => {
@@ -1684,8 +1689,13 @@ describe('Config', () => {
16841689
expect(config).to.have.nested.property('iast.redactionNamePattern', 'REDACTION_NAME_PATTERN')
16851690
expect(config).to.have.nested.property('iast.redactionValuePattern', 'REDACTION_VALUE_PATTERN')
16861691
expect(config).to.have.nested.property('iast.requestSampling', 30)
1687-
expect(config).to.have.nested.property('iast.securityControlsConfiguration',
1688-
'SANITIZER:CODE_INJECTION:sanitizer.js:method2')
1692+
if (DD_MAJOR < 6) {
1693+
expect(config).to.have.nested.property('iast.securityControlsConfiguration',
1694+
'SANITIZER:CODE_INJECTION:sanitizer.js:method2')
1695+
} else {
1696+
expect(config).to.have.nested.property('iast.securityControlsConfiguration',
1697+
'SANITIZER:CODE_INJECTION:sanitizer.js:method1')
1698+
}
16891699
expect(config).to.have.nested.property('iast.stackTrace.enabled', false)
16901700
expect(config).to.have.nested.property('llmobs.agentlessEnabled', false)
16911701
expect(config).to.have.nested.property('llmobs.mlApp', 'myOtherMlApp')

register.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,4 @@
55
const { register } = require('node:module')
66
const { pathToFileURL } = require('node:url')
77

8-
register('./loader-hook.mjs', pathToFileURL(__filename), {
9-
data: {
10-
exclude: [
11-
/langsmith/,
12-
/openai\/_shims/,
13-
/openai\/resources\/chat\/completions\/messages/,
14-
/openai\/agents-core\/dist\/shims/,
15-
/@anthropic-ai\/sdk\/_shims/
16-
]
17-
}
18-
})
8+
register('./loader-hook.mjs', pathToFileURL(__filename))

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,6 +2014,11 @@ escape-string-regexp@^4.0.0:
20142014
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
20152015
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
20162016

2017+
escape-string-regexp@^5.0.0:
2018+
version "5.0.0"
2019+
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
2020+
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
2021+
20172022
eslint-compat-utils@^0.5.1:
20182023
version "0.5.1"
20192024
resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4"

0 commit comments

Comments
 (0)