Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standalone ASM priority sampler and tag propagation #4416

Merged
merged 110 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
f14601e
DD_APM_TRACING_ENABLED and span _dd.apm.enabled tag
iunanua May 9, 2024
2817602
clean up
iunanua May 13, 2024
957760a
Use MANUAL_KEEP const
iunanua May 16, 2024
5d6210d
Add _dd.p.appsec tag on standalone ASM events
iunanua May 17, 2024
089c26d
Include apmTracingEnabled checks
iunanua May 20, 2024
18d9fef
Appsec Reporter tests
iunanua May 20, 2024
d903394
Appsec sdk track_event test
iunanua May 20, 2024
736014a
Use numeric value for _dd.p.appsec
iunanua May 20, 2024
396a8fc
Include appsec standalone config in .ts files
iunanua May 21, 2024
cb73c58
Clean up null and undefined values
iunanua May 21, 2024
67b171a
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua May 22, 2024
460d773
Remove not needed config properties
iunanua May 23, 2024
31f8951
standalone module
iunanua May 23, 2024
0b8a067
Clean up
iunanua May 23, 2024
dc1b7b9
standalone proxy test
iunanua May 23, 2024
626bbfa
Update packages/dd-trace/test/appsec/iast/vulnerability-reporter.spec.js
iunanua May 23, 2024
d989a73
appsec reporter test
iunanua May 23, 2024
7734ae7
Use standalone singletone in vulnerability-reporter
iunanua May 23, 2024
0ba2f3d
continue applying ratelimiter on appsec standalone events
iunanua May 23, 2024
4518d52
Update packages/dd-trace/src/appsec/reporter.js
iunanua May 23, 2024
167d5d5
Add _dd.apm.enabled:0 in root spans with remote parent
iunanua May 31, 2024
6f328fe
Use a method to add the tag
iunanua May 31, 2024
3627b99
Remove apmTracingEnabled config property
iunanua Jun 4, 2024
9a2a105
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua Jun 5, 2024
e57525d
Add _dd.p.appsec tag in trace tags
iunanua Jun 6, 2024
b15c51c
Some tests
iunanua Jun 6, 2024
5554ff7
Set _dd.apm.enabled in root span
iunanua Jun 6, 2024
f658168
configure standalone if _tracingInitialized
iunanua Jun 6, 2024
53b1dc0
Use dd-trace:span:start channel
iunanua Jun 7, 2024
366d2a7
PrioritySampler and propagation
iunanua Jun 6, 2024
a2e3a6c
Clean up
iunanua Jun 7, 2024
aa7d267
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 7, 2024
70f47bd
Clean up
iunanua Jun 7, 2024
05728b5
use a meta tag
iunanua Jun 10, 2024
d9ed33e
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 10, 2024
357b529
Use dc to modify what is injected and extracted
iunanua Jun 10, 2024
096a05f
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua Jun 10, 2024
e6a0098
set USER_KEEP priority
iunanua Jun 10, 2024
a50adbd
integration tests
iunanua Jun 10, 2024
9c4a3da
hasSubscribers check
iunanua Jun 10, 2024
b0ddeab
test description
iunanua Jun 10, 2024
19082d7
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 10, 2024
feacdc5
hasSubscribers check
iunanua Jun 10, 2024
3123e96
standalone tests
iunanua Jun 10, 2024
eea2b95
Check span context has tags before using them and check if config has…
iunanua Jun 10, 2024
80369e2
clean up
iunanua Jun 11, 2024
c3c9155
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 11, 2024
577d8d5
Pass prioritySampler as argument to DatadogTracer
iunanua Jun 11, 2024
c3ff8c5
clean up
iunanua Jun 11, 2024
a57af2d
clean up
iunanua Jun 11, 2024
63853cc
protect span context sampling access
iunanua Jun 11, 2024
3047443
Disable span stats if standalone enabled
iunanua Jun 11, 2024
d78018d
clean up
iunanua Jun 11, 2024
5919cf1
clean up
iunanua Jun 11, 2024
db4621d
Clean up
iunanua Jun 11, 2024
c37423a
Clean up
iunanua Jun 11, 2024
c999237
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 11, 2024
84087e6
Merge branch 'igor/standalone-asm-priority-sampler-channel' of github…
iunanua Jun 11, 2024
d0f154e
clean up
iunanua Jun 12, 2024
1a198f0
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 12, 2024
716409a
Remove all headers from carrier
iunanua Jun 12, 2024
fc5f682
inject integration tests
iunanua Jun 12, 2024
bd18133
remove only
iunanua Jun 12, 2024
d4fd15e
Update packages/dd-trace/test/appsec/sdk/track_event.spec.js
iunanua Jun 12, 2024
888c81f
Update packages/dd-trace/test/appsec/standalone.spec.js
iunanua Jun 12, 2024
58a9c6a
protect sample method
iunanua Jun 12, 2024
99675fb
Use assert instead expect
iunanua Jun 12, 2024
4e838a8
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 12, 2024
cbb5bb4
reset sampling prio
iunanua Jun 13, 2024
2a03d12
unsubscribe after test
iunanua Jun 13, 2024
9a94b39
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 13, 2024
0547b74
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua Jun 13, 2024
1043c2c
clear dd context from tracestate
iunanua Jun 14, 2024
0b82fe8
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua Jun 14, 2024
3b7398f
propagation with and without ASM events
iunanua Jun 18, 2024
999f136
Merge branch 'master' into igor/standalone-asm-config-and-tags
iunanua Jun 18, 2024
7dc9981
suggestions
iunanua Jun 18, 2024
446dde9
Merge branch 'igor/standalone-asm-config-and-tags' into igor/standalo…
iunanua Jun 18, 2024
b149c91
test inject and extrach channels
iunanua Jun 18, 2024
70b84e5
use two services to test propagation
iunanua Jun 18, 2024
7b9d1ae
integration tests cleanup
iunanua Jun 19, 2024
6a8d18b
clean up
iunanua Jun 19, 2024
a8873a1
Merge branch 'master' into igor/standalone-asm-priority-sampler-channel
iunanua Jun 19, 2024
5d0176d
clean up
iunanua Jun 20, 2024
9178acd
Update packages/dd-trace/src/priority_sampler.js
iunanua Jun 20, 2024
80eac9d
Update packages/dd-trace/src/appsec/standalone.js
iunanua Jun 20, 2024
5140402
Move hasOwn, remove not used argument and fix test
iunanua Jun 21, 2024
ff638cc
simplify iast integration-test using weak_hash
iunanua Jun 21, 2024
f0923fc
Update packages/dd-trace/src/appsec/standalone.js
iunanua Jun 21, 2024
af1744e
suggestions
iunanua Jun 21, 2024
dbd9c5e
Fix integration tests
iunanua Jun 21, 2024
63cd3b5
Update packages/dd-trace/test/span_stats.spec.js
iunanua Jun 21, 2024
1a19077
Update packages/dd-trace/test/exporters/agent/exporter.spec.js
iunanua Jun 21, 2024
cb8c080
Remove redundant check
iunanua Jun 21, 2024
c5910d1
Remove standalone option
iunanua Jun 21, 2024
3de92b4
protect onSpanInject and onSpanExtract
iunanua Jun 24, 2024
8db7a80
Merge branch 'master' into igor/standalone-asm-priority-sampler-channel
iunanua Jun 24, 2024
2fbc1cf
Merge branch 'master' into igor/standalone-asm-priority-sampler-channel
iunanua Jun 25, 2024
37ed990
do not set _dd.p.dm
iunanua Jun 25, 2024
8d8b5c7
remove _dd.p.dm check from integration tests
iunanua Jun 25, 2024
81700d0
increase coverage
iunanua Jun 26, 2024
ef29a62
increase coverage
iunanua Jun 26, 2024
3288f77
more coverage
iunanua Jun 26, 2024
adfae02
remove not needed async
iunanua Jul 1, 2024
ccca78c
set default mechanism
iunanua Jul 2, 2024
9a8f4e8
sugestions
iunanua Jul 2, 2024
5ab27e7
Remove throw tests
iunanua Jul 2, 2024
f615a16
Remove throw tests
iunanua Jul 2, 2024
ea548ea
Update packages/dd-trace/test/appsec/standalone.spec.js
iunanua Jul 2, 2024
61f7b11
Merge branch 'master' into igor/standalone-asm-priority-sampler-channel
iunanua Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 301 additions & 0 deletions integration-tests/standalone-asm.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
'use strict'

const { assert } = require('chai')
const path = require('path')

const {
createSandbox,
FakeAgent,
spawnProc,
curlAndAssertMessage,
curl
} = require('./helpers')

describe('Standalone ASM', () => {
let sandbox, cwd, startupTestFile, agent, proc, env
before(async () => {
uurien marked this conversation as resolved.
Show resolved Hide resolved
sandbox = await createSandbox(['express'], true)
uurien marked this conversation as resolved.
Show resolved Hide resolved
cwd = sandbox.folder
startupTestFile = path.join(cwd, 'standalone-asm/index.js')
})

after(async () => {
await sandbox.remove()
})

context('enabled', () => {
iunanua marked this conversation as resolved.
Show resolved Hide resolved
beforeEach(async () => {
agent = await new FakeAgent().start()

env = {
AGENT_PORT: agent.port,
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED: 'true'
}

const execArgv = []

proc = await spawnProc(startupTestFile, { cwd, env, execArgv })
})

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

function assertKeep (payload, manual = true) {
const { meta, metrics } = payload
assert.propertyVal(meta, '_dd.p.dm', '-5')
if (manual) {
iunanua marked this conversation as resolved.
Show resolved Hide resolved
assert.propertyVal(meta, 'manual.keep', 'true')
}
assert.propertyVal(meta, '_dd.p.appsec', '1')

assert.propertyVal(metrics, '_sampling_priority_v1', 2)
assert.propertyVal(metrics, '_dd.apm.enabled', 0)
}

function assertDrop (payload) {
const { metrics } = payload
assert.propertyVal(metrics, '_sampling_priority_v1', 0)
assert.propertyVal(metrics, '_dd.apm.enabled', 0)
assert.notProperty(metrics, '_dd.p.appsec')
}

async function doWarmupRequests (procOrUrl, number = 3) {
for (let i = number; i > 0; i--) {
await curl(procOrUrl)
}
}

// first req initializes the waf and reports the first appsec event adding manual.keep tag
it('should send correct headers and tags on first req', async () => {
return curlAndAssertMessage(agent, proc, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 1)
assert.isArray(payload[0])

// express.request + 4 middlewares
assert.strictEqual(payload[0].length, 5)

assertKeep(payload[0][0])
})
})

it('should keep second req because RateLimiter allows 1 req/min and discard the next', async () => {
// 1st req kept because waf init
// 2nd req kept because it's the first one hitting RateLimiter
// next in the first minute are dropped
await doWarmupRequests(proc)

return curlAndAssertMessage(agent, proc, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 4)

const secondReq = payload[1]
assert.isArray(secondReq)
assert.strictEqual(secondReq.length, 5)

const { meta, metrics } = secondReq[0]
assert.propertyVal(meta, '_dd.p.dm', '-5')
assert.notProperty(meta, 'manual.keep')
assert.notProperty(meta, '_dd.p.appsec')

assert.propertyVal(metrics, '_sampling_priority_v1', 1)
assert.propertyVal(metrics, '_dd.apm.enabled', 0)

assertDrop(payload[2][0])

assertDrop(payload[3][0])
})
})

it('should keep attack requests', async () => {
await doWarmupRequests(proc)

const urlAttack = proc.url + '?query=1 or 1=1'
return curlAndAssertMessage(agent, urlAttack, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 4)

assertKeep(payload[3][0])
})
})

it('should keep sdk events', async () => {
await doWarmupRequests(proc)

const url = proc.url + '/login?user=test'
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 4)

assertKeep(payload[3][0])
})
})

it('should keep custom sdk events', async () => {
await doWarmupRequests(proc)

const url = proc.url + '/sdk'
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 4)

assertKeep(payload[3][0])
})
})

it('should keep iast events', async () => {
await doWarmupRequests(proc)

const url = proc.url + '/vulnerableReadFile?filename=./readFile.js'
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)
assert.strictEqual(payload.length, 4)

const expressReq4 = payload[3][0]
assertKeep(expressReq4)
assert.property(expressReq4.meta, '_dd.iast.json')
assert.propertyVal(expressReq4.metrics, '_dd.iast.enabled', 1)
})
})

context('propagation', () => {
let proc2
let port2

beforeEach(async () => {
const execArgv = []

proc2 = await spawnProc(startupTestFile, { cwd, env, execArgv })

port2 = parseInt(proc2.url.substring(proc2.url.lastIndexOf(':') + 1), 10)
})

afterEach(async () => {
proc2.kill()
})

// proc/drop-and-call-sdk:
// after setting a manual.drop calls to downstream proc2/sdk which triggers an appsec event
it('should keep trace even if parent prio is -1 but there is an event in the local trace', async () => {
await doWarmupRequests(proc2)

const url = `${proc.url}/propagation-after-drop-and-call-sdk?port=${port2}`
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)

const innerReq = payload.find(p => p[0].resource === 'GET /sdk')
assert.notStrictEqual(innerReq, undefined)
assertKeep(innerReq[0])
}, undefined, undefined, true)
})

// proc/propagation-with-event triggers an appsec ev and calls downstream proc2/down with no event
it('should keep if parent trace is (prio:2, _dd.p.appsec:1) but there is no ev in the local trace', async () => {
iunanua marked this conversation as resolved.
Show resolved Hide resolved
await doWarmupRequests(proc)

const url = `${proc.url}/propagation-without-event?port=${port2}`
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)

const innerReq = payload.find(p => p[0].resource === 'GET /down')
assert.notStrictEqual(innerReq, undefined)
assertKeep(innerReq[0])
}, undefined, undefined, true)
})

it('should remove parent trace data if there is no ev in the local trace', async () => {
simon-id marked this conversation as resolved.
Show resolved Hide resolved
await doWarmupRequests(proc)

const url = `${proc.url}/propagation-without-event?port=${port2}`
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)

const innerReq = payload.find(p => p[0].resource === 'GET /down')
assert.notStrictEqual(innerReq, undefined)
assert.notProperty(innerReq[0].meta, '_dd.p.other')
}, undefined, undefined, true)
})

it('should not remove parent trace data if there is ev in the local trace', async () => {
await doWarmupRequests(proc)

const url = `${proc.url}/propagation-with-event?port=${port2}`
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.propertyVal(headers, 'datadog-client-computed-stats', 'yes')
assert.isArray(payload)

const innerReq = payload.find(p => p[0].resource === 'GET /down')
assert.notStrictEqual(innerReq, undefined)
assert.property(innerReq[0].meta, '_dd.p.other')
}, undefined, undefined, true)
})
})
})

context('disabled', () => {
beforeEach(async () => {
agent = await new FakeAgent().start()

env = {
AGENT_PORT: agent.port
}

proc = await spawnProc(startupTestFile, { cwd, env })
})

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

it('should not add standalone related tags in iast events', () => {
const url = proc.url + '/vulnerableReadFile?filename=./readFile.js'
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
assert.notProperty(headers, 'datadog-client-computed-stats')
assert.isArray(payload)
assert.strictEqual(payload.length, 1)
assert.isArray(payload[0])

// express.request + 4 middlewares
assert.strictEqual(payload[0].length, 5)

const { meta, metrics } = payload[0][0]
assert.property(meta, '_dd.iast.json') // PATH_TRAVERSAL and XCONTENTTYPE_HEADER_MISSING reported

assert.notProperty(meta, '_dd.p.appsec')
assert.notProperty(metrics, '_dd.apm.enabled')
})
})

it('should not add standalone related tags in appsec events', () => {
const urlAttack = proc.url + '?query=1 or 1=1'

return curlAndAssertMessage(agent, urlAttack, ({ headers, payload }) => {
assert.notProperty(headers, 'datadog-client-computed-stats')
assert.isArray(payload)
assert.strictEqual(payload.length, 1)
assert.isArray(payload[0])

// express.request + 4 middlewares
assert.strictEqual(payload[0].length, 5)

const { meta, metrics } = payload[0][0]
assert.property(meta, '_dd.appsec.json') // crs-942-100 triggered

assert.notProperty(meta, '_dd.p.appsec')
assert.notProperty(metrics, '_dd.apm.enabled')
})
})
})
})
14 changes: 14 additions & 0 deletions integration-tests/standalone-asm/iast-vulnerable-readFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { readFileSync } = require('fs')

function readFile (filename) {
try {
// eslint-disable-next-line n/no-path-concat
return readFileSync(__dirname + '/' + filename).toString()
} catch (e) {
// do nothing
}
}

module.exports = {
readFile
}
Loading
Loading