Skip to content

Commit

Permalink
Merge branch 'master' into khanayan123/trace-128-bit-consistency
Browse files Browse the repository at this point in the history
  • Loading branch information
khanayan123 authored Feb 19, 2025
2 parents 4f1f1d9 + f06fb27 commit 306434f
Show file tree
Hide file tree
Showing 143 changed files with 4,413 additions and 597 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/system-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
uses: DataDog/system-tests/.github/workflows/compute-workflow-parameters.yml@main
with:
library: nodejs
scenarios_groups: essentials,appsec_rasp
scenarios_groups: essentials,appsec_rasp,debugger

system-tests:
runs-on: ${{ contains(fromJSON('["CROSSED_TRACING_LIBRARIES", "INTEGRATIONS"]'), matrix.scenario) && 'ubuntu-latest-16-cores' || 'ubuntu-latest' }}
Expand Down
2 changes: 1 addition & 1 deletion .gitlab/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ variables:
tags: ["runner:apm-k8s-tweaked-metal"]
image: $MICROBENCHMARKS_CI_IMAGE
interruptible: true
timeout: 15m
timeout: 20m
script:
- git clone --branch dd-trace-js https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.ddbuild.io/DataDog/benchmarking-platform platform && cd platform
- bp-runner bp-runner.yml --debug
Expand Down
3 changes: 2 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require,protobufjs,BSD-3-Clause,Copyright 2016 Daniel Wirtz
require,tlhunter-sorted-set,MIT,Copyright (c) 2023 Datadog Inc.
require,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
require,rfdc,MIT,Copyright 2019 David Mark Clements
require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
require,semifies,Apache license 2.0,Copyright Authors
require,shell-quote,mit,Copyright (c) 2013 James Halliday
require,source-map,BSD-3-Clause,Copyright (c) 2009-2011, Mozilla Foundation and contributors
require,ttl-set,MIT,Copyright (c) 2024 Thomas Watson
Expand Down Expand Up @@ -68,6 +68,7 @@ dev,nock,MIT,Copyright 2017 Pedro Teixeira and other contributors
dev,nyc,ISC,Copyright 2015 Contributors
dev,proxyquire,MIT,Copyright 2013 Thorsten Lorenz
dev,rimraf,ISC,Copyright Isaac Z. Schlueter and Contributors
dev,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
dev,tap,ISC,Copyright 2011-2022 Isaac Z. Schlueter and Contributors
Expand Down
6 changes: 2 additions & 4 deletions benchmark/sirun/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@ RUN wget -O sirun.tar.gz https://github.com/DataDog/sirun/releases/download/v0.1
RUN mkdir -p /usr/local/nvm \
&& wget -q -O - https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install --no-progress 14.21.3 \
&& nvm install --no-progress 16.20.1 \
&& nvm install --no-progress 18.16.1 \
&& nvm install --no-progress 20.4.0 \
&& nvm install --no-progress 22.10.0 \
&& nvm alias default 18 \
&& nvm use 18
&& nvm alias default 22 \
&& nvm use 22

RUN mkdir /opt/insecure-bank-js
RUN git clone --depth 1 https://github.com/hdiv/insecure-bank-js.git /opt/insecure-bank-js
Expand Down
2 changes: 1 addition & 1 deletion benchmark/sirun/plugin-graphql/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"run": "node index.js",
"run_with_affinity": "bash -c \"taskset -c $CPU_AFFINITY node index.js\"",
"cachegrind": false,
"iterations": 2,
"iterations": 30,
"instructions": true,
"variants": {
"control": {},
Expand Down
4 changes: 2 additions & 2 deletions benchmark/sirun/plugin-graphql/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const Human = new graphql.GraphQLObjectType({
async resolve (obj, args) {
const promises = []

for (let i = 0; i < 100; i++) {
for (let i = 0; i < 20; i++) {
promises.push(await Promise.resolve({}))
}

Expand All @@ -115,7 +115,7 @@ const schema = new graphql.GraphQLSchema({
async resolve (obj, args) {
const promises = []

for (let i = 0; i < 100; i++) {
for (let i = 0; i < 20; i++) {
promises.push(await Promise.resolve({}))
}

Expand Down
4 changes: 2 additions & 2 deletions ci/init.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
const tracer = require('../packages/dd-trace')
const { isTrue } = require('../packages/dd-trace/src/util')
const { isTrue, isFalse } = require('../packages/dd-trace/src/util')
const log = require('../packages/dd-trace/src/log')

const isJestWorker = !!process.env.JEST_WORKER_ID
Expand All @@ -23,7 +23,7 @@ const options = {
flushInterval: isJestWorker ? 0 : 5000
}

let shouldInit = true
let shouldInit = !isFalse(process.env.DD_CIVISIBILITY_ENABLED)

if (isPackageManager()) {
log.debug('dd-trace is not initialized in a package manager.')
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ services:
ports:
- "127.0.0.1:6379:6379"
mongo:
image: circleci/mongo:3.6
image: circleci/mongo:4.4
platform: linux/amd64
ports:
- "127.0.0.1:27017:27017"
Expand Down
28 changes: 27 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({ baseDirectory: __dirname })

const SRC_FILES = [
'*.js',
'*.mjs',
'ext/**/*.js',
'ext/**/*.mjs',
'packages/*/src/**/*.js',
'packages/*/src/**/*.mjs'
]

const TEST_FILES = [
'packages/*/test/**/*.js',
'packages/*/test/**/*.mjs',
Expand All @@ -32,9 +41,10 @@ export default [
'**/versions', // This is effectively a node_modules tree.
'**/acmeair-nodejs', // We don't own this.
'**/vendor', // Generally, we didn't author this code.
'integration-tests/debugger/target-app/source-map-support/minify.min.js', // Generated
'integration-tests/debugger/target-app/source-map-support/typescript.js', // Generated
'integration-tests/esbuild/out.js', // Generated
'integration-tests/esbuild/aws-sdk-out.js', // Generated
'packages/dd-trace/src/appsec/blocked_templates.js', // TODO Why is this ignored?
'packages/dd-trace/src/payload-tagging/jsonpath-plus.js' // Vendored
]
},
Expand Down Expand Up @@ -83,6 +93,22 @@ export default [
...mocha.configs.flat.recommended,
files: TEST_FILES
},
{
name: 'dd-trace/src/all',
files: SRC_FILES,
rules: {
'n/no-restricted-require': ['error', [
{
name: 'diagnostics_channel',
message: 'Please use dc-polyfill instead.'
},
{
name: 'semver',
message: 'Please use semifies instead.'
}
]]
}
},
{
name: 'dd-trace/tests/all',
files: TEST_FILES,
Expand Down
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2226,6 +2226,11 @@ declare namespace tracer {
*/
redactionValuePattern?: string,

/**
* Allows to enable security controls.
*/
securityControlsConfiguration?: string,

/**
* Specifies the verbosity of the sent telemetry. Default 'INFORMATION'
*/
Expand Down
69 changes: 69 additions & 0 deletions integration-tests/appsec/esm-security-controls/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use strict'

import childProcess from 'node:child_process'
import express from 'express'
import { sanitize } from './sanitizer.mjs'
import sanitizeDefault from './sanitizer-default.mjs'
import { validate, validateNotConfigured } from './validator.mjs'

const app = express()
const port = process.env.APP_PORT || 3000

app.get('/cmdi-s-secure', (req, res) => {
const command = sanitize(req.query.command)
try {
childProcess.execSync(command)
} catch (e) {
// ignore
}

res.end()
})

app.get('/cmdi-s-secure-comparison', (req, res) => {
const command = sanitize(req.query.command)
try {
childProcess.execSync(command)
} catch (e) {
// ignore
}

try {
childProcess.execSync(req.query.command)
} catch (e) {
// ignore
}

res.end()
})

app.get('/cmdi-s-secure-default', (req, res) => {
const command = sanitizeDefault(req.query.command)
try {
childProcess.execSync(command)
} catch (e) {
// ignore
}

res.end()
})

app.get('/cmdi-iv-insecure', (req, res) => {
if (validateNotConfigured(req.query.command)) {
childProcess.execSync(req.query.command)
}

res.end()
})

app.get('/cmdi-iv-secure', (req, res) => {
if (validate(req.query.command)) {
childProcess.execSync(req.query.command)
}

res.end()
})

app.listen(port, () => {
process.send({ port })
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

function sanitizeDefault (input) {
return input
}

export default sanitizeDefault
5 changes: 5 additions & 0 deletions integration-tests/appsec/esm-security-controls/sanitizer.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict'

export function sanitize (input) {
return input
}
9 changes: 9 additions & 0 deletions integration-tests/appsec/esm-security-controls/validator.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

export function validate (input) {
return true
}

export function validateNotConfigured (input) {
return true
}
126 changes: 126 additions & 0 deletions integration-tests/appsec/iast.esm-security-controls.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
'use strict'

const { createSandbox, spawnProc, FakeAgent } = require('../helpers')
const path = require('path')
const getPort = require('get-port')
const Axios = require('axios')
const { assert } = require('chai')

describe('ESM Security controls', () => {
let axios, sandbox, cwd, appPort, appFile, agent, proc

before(async function () {
this.timeout(process.platform === 'win32' ? 90000 : 30000)
sandbox = await createSandbox(['express'])
appPort = await getPort()
cwd = sandbox.folder
appFile = path.join(cwd, 'appsec', 'esm-security-controls', 'index.mjs')

axios = Axios.create({
baseURL: `http://localhost:${appPort}`
})
})

after(async function () {
await sandbox.remove()
})

const nodeOptions = '--import dd-trace/initialize.mjs'

beforeEach(async () => {
agent = await new FakeAgent().start()

proc = await spawnProc(appFile, {
cwd,
env: {
DD_TRACE_AGENT_PORT: agent.port,
APP_PORT: appPort,
DD_IAST_ENABLED: 'true',
DD_IAST_REQUEST_SAMPLING: '100',
// eslint-disable-next-line no-multi-str
DD_IAST_SECURITY_CONTROLS_CONFIGURATION: '\
SANITIZER:COMMAND_INJECTION:appsec/esm-security-controls/sanitizer.mjs:sanitize;\
SANITIZER:COMMAND_INJECTION:appsec/esm-security-controls/sanitizer-default.mjs;\
INPUT_VALIDATOR:*:appsec/esm-security-controls/validator.mjs:validate',
NODE_OPTIONS: nodeOptions
}
})
})

afterEach(async () => {
proc.kill()
await agent.stop()
})

it('test endpoint with iv not configured does have COMMAND_INJECTION vulnerability', async function () {
await axios.get('/cmdi-iv-insecure?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.property(span.meta, '_dd.iast.json')
assert.include(span.meta['_dd.iast.json'], '"COMMAND_INJECTION"')
})
}, null, 1, true)
})

it('test endpoint sanitizer does not have COMMAND_INJECTION vulnerability', async () => {
await axios.get('/cmdi-s-secure?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.notProperty(span.meta, '_dd.iast.json')
assert.property(span.metrics, '_dd.iast.telemetry.suppressed.vulnerabilities.command_injection')
})
}, null, 1, true)
})

it('test endpoint with default sanitizer does not have COMMAND_INJECTION vulnerability', async () => {
await axios.get('/cmdi-s-secure-default?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.notProperty(span.meta, '_dd.iast.json')
assert.property(span.metrics, '_dd.iast.telemetry.suppressed.vulnerabilities.command_injection')
})
}, null, 1, true)
})

it('test endpoint with default sanitizer does have COMMAND_INJECTION with original tainted', async () => {
await axios.get('/cmdi-s-secure-comparison?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.property(span.meta, '_dd.iast.json')
assert.include(span.meta['_dd.iast.json'], '"COMMAND_INJECTION"')
})
}, null, 1, true)
})

it('test endpoint with default sanitizer does have COMMAND_INJECTION vulnerability', async () => {
await axios.get('/cmdi-s-secure-default?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.notProperty(span.meta, '_dd.iast.json')
assert.property(span.metrics, '_dd.iast.telemetry.suppressed.vulnerabilities.command_injection')
})
}, null, 1, true)
})

it('test endpoint with iv does not have COMMAND_INJECTION vulnerability', async () => {
await axios.get('/cmdi-iv-secure?command=ls -la')

await agent.assertMessageReceived(({ payload }) => {
const spans = payload.flatMap(p => p.filter(span => span.name === 'express.request'))
spans.forEach(span => {
assert.notProperty(span.meta, '_dd.iast.json')
assert.property(span.metrics, '_dd.iast.telemetry.suppressed.vulnerabilities.command_injection')
})
}, null, 1, true)
})
})
Loading

0 comments on commit 306434f

Please sign in to comment.