diff --git a/integration-tests/appsec/data-collection/data-collection-rules.json b/integration-tests/appsec/data-collection/data-collection-rules.json index b1ea9c21f6b..63dfe9d049a 100644 --- a/integration-tests/appsec/data-collection/data-collection-rules.json +++ b/integration-tests/appsec/data-collection/data-collection-rules.json @@ -27,6 +27,43 @@ "operator": "match_regex" } ] + }, + { + "id": "trace_tagging_rule", + "name": "Trace tagging test rule", + "tags": { + "type": "security_scanner", + "category": "attack_attempt" + }, + "conditions": [ + { + "parameters": { + "inputs": [ + { + "address": "server.request.headers.no_cookies", + "key_path": [ + "user-agent" + ] + } + ], + "regex": "^TraceTaggingTest\\/v" + }, + "operator": "match_regex" + } + ], + "output": { + "event": false, + "keep": true, + "attributes": { + "_dd.appsec.trace.integer": { + "value": 1234 + }, + "_dd.appsec.trace.agent": { + "address": "server.request.headers.no_cookies", + "key_path": ["user-agent"] + } + } + } } ] } diff --git a/integration-tests/appsec/trace-tagging.spec.js b/integration-tests/appsec/trace-tagging.spec.js new file mode 100644 index 00000000000..c46fcadf664 --- /dev/null +++ b/integration-tests/appsec/trace-tagging.spec.js @@ -0,0 +1,95 @@ +'use strict' + +const { assert } = require('chai') +const path = require('path') +const Axios = require('axios') + +const { + createSandbox, + FakeAgent, + spawnProc +} = require('../helpers') + +describe('ASM Trace Tagging rules', () => { + let axios, sandbox, cwd, appFile, agent, proc + + function startServer () { + beforeEach(async () => { + agent = await new FakeAgent().start() + + const env = { + DD_TRACE_AGENT_PORT: agent.port, + DD_APPSEC_ENABLED: true, + DD_APPSEC_RULES: path.join(cwd, 'appsec', 'data-collection', 'data-collection-rules.json') + } + + proc = await spawnProc(appFile, { cwd, env, execArgv: [] }) + axios = Axios.create({ baseURL: proc.url }) + }) + + afterEach(async () => { + proc.kill() + await agent.stop() + }) + } + + describe('express', () => { + before(async () => { + sandbox = await createSandbox(['express']) + cwd = sandbox.folder + appFile = path.join(cwd, 'appsec/data-collection/index.js') + }) + + after(async () => { + await sandbox.remove() + }) + + startServer() + + it('should report waf attributes', async () => { + await axios.get('/', { headers: { 'User-Agent': 'TraceTaggingTest/v1' } }) + + await agent.assertMessageReceived(({ _, payload }) => { + assert.property(payload[0][0].meta, '_dd.appsec.trace.agent') + assert.strictEqual(payload[0][0].meta['_dd.appsec.trace.agent'], 'TraceTaggingTest/v1') + assert.property(payload[0][0].metrics, '_dd.appsec.trace.integer') + assert.strictEqual(payload[0][0].metrics['_dd.appsec.trace.integer'], 1234) + }) + }) + }) + + describe('fastify', () => { + before(async () => { + sandbox = await createSandbox(['fastify']) + cwd = sandbox.folder + appFile = path.join(cwd, 'appsec/data-collection/fastify.js') + }) + + after(async () => { + await sandbox.remove() + }) + + startServer() + + it('should report waf attributes', async () => { + let fastifyRequestReceived = false + + await axios.get('/', { headers: { 'User-Agent': 'TraceTaggingTest/v1' } }) + + await agent.assertMessageReceived(({ _, payload }) => { + if (payload[0][0].name !== 'fastify.request') { + throw new Error('Not the span we are looking for') + } + + fastifyRequestReceived = true + + assert.property(payload[0][0].meta, '_dd.appsec.trace.agent') + assert.strictEqual(payload[0][0].meta['_dd.appsec.trace.agent'], 'TraceTaggingTest/v1') + assert.property(payload[0][0].metrics, '_dd.appsec.trace.integer') + assert.strictEqual(payload[0][0].metrics['_dd.appsec.trace.integer'], 1234) + }, 30000, 10, true) + + assert.isTrue(fastifyRequestReceived) + }) + }) +}) diff --git a/package.json b/package.json index 5e270da20bb..494200db625 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ ], "dependencies": { "@datadog/libdatadog": "0.7.0", - "@datadog/native-appsec": "10.0.0", + "@datadog/native-appsec": "10.0.1", "@datadog/native-iast-taint-tracking": "4.0.0", "@datadog/native-metrics": "3.1.1", "@datadog/pprof": "5.9.0", diff --git a/packages/dd-trace/src/appsec/reporter.js b/packages/dd-trace/src/appsec/reporter.js index d4e820592a8..af806041e43 100644 --- a/packages/dd-trace/src/appsec/reporter.js +++ b/packages/dd-trace/src/appsec/reporter.js @@ -3,7 +3,6 @@ const dc = require('dc-polyfill') const zlib = require('zlib') -const Limiter = require('../rate_limiter') const { storage } = require('../../../datadog-core') const web = require('../plugins/util/web') const { ipHeaderList } = require('../plugins/util/ip_extractor') @@ -15,7 +14,6 @@ const { updateWafRequestsMetricTags, updateRaspRequestsMetricTags, updateRaspRuleSkippedMetricTags, - updateRateLimitedMetric, getRequestMetrics } = require('./telemetry') const { keepTrace } = require('../priority_sampler') @@ -31,9 +29,6 @@ const COLLECTED_REQUEST_BODY_MAX_ELEMENTS_PER_NODE = 256 const telemetryLogCh = dc.channel('datadog:telemetry:log') -// default limiter, configurable with setRateLimit() -let limiter = new Limiter(100) - const config = { headersExtendedCollectionEnabled: false, maxHeadersCollected: 0, @@ -91,7 +86,6 @@ const NON_EXTENDED_REQUEST_HEADERS = new Set([...requestHeadersList, ...eventHea const NON_EXTENDED_RESPONSE_HEADERS = new Set(contentHeaderList) function init (_config) { - limiter = new Limiter(_config.rateLimit) config.headersExtendedCollectionEnabled = _config.extendedHeadersCollection.enabled config.maxHeadersCollected = _config.extendedHeadersCollection.maxHeaders config.headersRedaction = _config.extendedHeadersCollection.redaction @@ -325,12 +319,6 @@ function reportAttack (attackData) { 'appsec.event': 'true' } - if (limiter.isAllowed()) { - keepTrace(rootSpan, ASM) - } else { - updateRateLimitedMetric(req) - } - // TODO: maybe add this to format.js later (to take decision as late as possible) if (!currentTags['_dd.origin']) { newTags['_dd.origin'] = 'appsec' @@ -430,8 +418,8 @@ function isRaspAttack (events) { return events.some(e => e.rule?.tags?.module === 'rasp') } -function isFingerprintAttribute (attribute) { - return attribute.startsWith('_dd.appsec.fp') +function isSchemaAttribute (attribute) { + return attribute.startsWith('_dd.appsec.s.') } function reportAttributes (attributes) { @@ -444,7 +432,7 @@ function reportAttributes (attributes) { const tags = {} for (let [tag, value] of Object.entries(attributes)) { - if (!isFingerprintAttribute(tag)) { + if (isSchemaAttribute(tag)) { const gzippedValue = zlib.gzipSync(JSON.stringify(value)) value = gzippedValue.toString('base64') } diff --git a/packages/dd-trace/src/appsec/waf/index.js b/packages/dd-trace/src/appsec/waf/index.js index 3d08fee257d..a2035073f73 100644 --- a/packages/dd-trace/src/appsec/waf/index.js +++ b/packages/dd-trace/src/appsec/waf/index.js @@ -3,6 +3,11 @@ const { storage } = require('../../../../datadog-core') const log = require('../../log') const Reporter = require('../reporter') +const Limiter = require('../../rate_limiter') +const { keepTrace } = require('../../priority_sampler') +const { ASM } = require('../../standalone/product') +const web = require('../../plugins/util/web') +const { updateRateLimitedMetric } = require('../telemetry') class WafUpdateError extends Error { constructor (diagnosticErrors) { @@ -12,6 +17,8 @@ class WafUpdateError extends Error { } } +let limiter = new Limiter(100) + const waf = { wafManager: null, init, @@ -27,6 +34,8 @@ const waf = { function init (rules, config) { destroy() + limiter = new Limiter(config.rateLimit) + // dirty require to make startup faster for serverless const WAFManager = require('./waf_manager') @@ -99,8 +108,18 @@ function run (data, req, raspRule) { } const wafContext = waf.wafManager.getWAFContext(req) + const result = wafContext.run(data, raspRule) + + if (result?.keep) { + if (limiter.isAllowed()) { + const rootSpan = web.root(req) + keepTrace(rootSpan, ASM) + } else { + updateRateLimitedMetric(req) + } + } - return wafContext.run(data, raspRule) + return result } function disposeContext (req) { diff --git a/packages/dd-trace/src/remote_config/capabilities.js b/packages/dd-trace/src/remote_config/capabilities.js index 61a6e6ae09d..60da687e069 100644 --- a/packages/dd-trace/src/remote_config/capabilities.js +++ b/packages/dd-trace/src/remote_config/capabilities.js @@ -28,5 +28,6 @@ module.exports = { ASM_NETWORK_FINGERPRINT: 1n << 34n, ASM_HEADER_FINGERPRINT: 1n << 35n, ASM_RASP_CMDI: 1n << 37n, - ASM_DD_MULTICONFIG: 1n << 42n + ASM_DD_MULTICONFIG: 1n << 42n, + ASM_TRACE_TAGGING_RULES: 1n << 43n, } diff --git a/packages/dd-trace/src/remote_config/index.js b/packages/dd-trace/src/remote_config/index.js index 255803f73ea..aa27801a258 100644 --- a/packages/dd-trace/src/remote_config/index.js +++ b/packages/dd-trace/src/remote_config/index.js @@ -94,6 +94,7 @@ function enableWafUpdate (appsecConfig) { rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, true) rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, true) rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, true) + rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true) if (appsecConfig.rasp?.enabled) { rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, true) @@ -130,6 +131,7 @@ function disableWafUpdate () { rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, false) rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, false) rc.updateCapabilities(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, false) + rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, false) rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SQLI, false) rc.updateCapabilities(RemoteConfigCapabilities.ASM_RASP_SSRF, false) diff --git a/packages/dd-trace/test/appsec/reporter.spec.js b/packages/dd-trace/test/appsec/reporter.spec.js index a9bb98b62e9..11d34e8b86b 100644 --- a/packages/dd-trace/test/appsec/reporter.spec.js +++ b/packages/dd-trace/test/appsec/reporter.spec.js @@ -396,8 +396,6 @@ describe('reporter', () => { '_dd.origin': 'appsec', '_dd.appsec.json': '{"triggers":[{"rule":{},"rule_matches":[{}]}]}' }) - expect(prioritySampler.setPriority).to.have.been.calledOnceWithExactly(span, USER_KEEP, ASM) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called }) it('should add tags to request span', () => { @@ -416,40 +414,6 @@ describe('reporter', () => { '_dd.appsec.json': '{"triggers":[{"rule":{},"rule_matches":[{}]}]}', 'network.client.ip': '8.8.8.8' }) - expect(prioritySampler.setPriority).to.have.been.calledOnceWithExactly(span, USER_KEEP, ASM) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called - }) - - it('should not add manual.keep when rate limit is reached', (done) => { - const addTags = span.addTags - - expect(Reporter.reportAttack([])).to.not.be.false - expect(Reporter.reportAttack([])).to.not.be.false - expect(Reporter.reportAttack([])).to.not.be.false - - expect(prioritySampler.setPriority).to.have.callCount(3) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called - - const reporterConfigWithRateLimit1 = Object.assign({}, defaultReporterConfig) - reporterConfigWithRateLimit1.rateLimit = 1 - Reporter.init(reporterConfigWithRateLimit1) - - expect(Reporter.reportAttack([])).to.not.be.false - expect(addTags.getCall(3).firstArg).to.have.property('appsec.event').that.equals('true') - expect(prioritySampler.setPriority).to.have.callCount(4) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called - - expect(Reporter.reportAttack([])).to.not.be.false - expect(addTags.getCall(4).firstArg).to.have.property('appsec.event').that.equals('true') - expect(prioritySampler.setPriority).to.have.callCount(4) - expect(telemetry.updateRateLimitedMetric).to.be.calledOnceWithExactly(req) - - setTimeout(() => { - expect(Reporter.reportAttack([])).to.not.be.false - expect(prioritySampler.setPriority).to.have.callCount(5) - expect(telemetry.updateRateLimitedMetric).to.be.calledOnceWithExactly(req) - done() - }, 1020) }) it('should not overwrite origin tag', () => { @@ -464,8 +428,6 @@ describe('reporter', () => { '_dd.appsec.json': '{"triggers":[]}', 'network.client.ip': '8.8.8.8' }) - expect(prioritySampler.setPriority).to.have.been.calledOnceWithExactly(span, USER_KEEP, ASM) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called }) it('should merge attacks json', () => { @@ -489,8 +451,6 @@ describe('reporter', () => { '_dd.appsec.json': '{"triggers":[{"rule":{},"rule_matches":[{}]},{"rule":{}},{"rule":{},"rule_matches":[{}]}]}', 'network.client.ip': '8.8.8.8' }) - expect(prioritySampler.setPriority).to.have.been.calledOnceWithExactly(span, USER_KEEP, ASM) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called }) it('should call standalone sample', () => { @@ -514,9 +474,6 @@ describe('reporter', () => { '_dd.appsec.json': '{"triggers":[{"rule":{},"rule_matches":[{}]},{"rule":{}},{"rule":{},"rule_matches":[{}]}]}', 'network.client.ip': '8.8.8.8' }) - - expect(prioritySampler.setPriority).to.have.been.calledOnceWithExactly(span, USER_KEEP, ASM) - expect(telemetry.updateRateLimitedMetric).to.not.have.been.called }) describe('extended collection', () => { @@ -719,7 +676,8 @@ describe('reporter', () => { '_dd.appsec.s.req.params': schemaValue, '_dd.appsec.s.req.cookies': schemaValue, '_dd.appsec.s.req.body': schemaValue, - 'custom.processor.output': schemaValue + 'custom.processor.output': 'custom_attribute', + 'custom.processor.output_int': 42 } Reporter.reportAttributes(attributes) @@ -735,7 +693,8 @@ describe('reporter', () => { '_dd.appsec.s.req.params': schemaEncoded, '_dd.appsec.s.req.cookies': schemaEncoded, '_dd.appsec.s.req.body': schemaEncoded, - 'custom.processor.output': schemaEncoded + 'custom.processor.output': 'custom_attribute', + 'custom.processor.output_int': 42 }) }) }) diff --git a/packages/dd-trace/test/appsec/waf/index.spec.js b/packages/dd-trace/test/appsec/waf/index.spec.js index 6754e253dc3..eb96334d426 100644 --- a/packages/dd-trace/test/appsec/waf/index.spec.js +++ b/packages/dd-trace/test/appsec/waf/index.spec.js @@ -5,7 +5,6 @@ const proxyquire = require('proxyquire') const Config = require('../../../src/config') const rules = require('../../../src/appsec/recommended.json') const Reporter = require('../../../src/appsec/reporter') -const web = require('../../../src/plugins/util/web') describe('WAF Manager', () => { const knownAddresses = new Set([ @@ -20,10 +19,18 @@ describe('WAF Manager', () => { let DDWAF let config let webContext + let keepTrace, updateRateLimitedMetric, limiterStub beforeEach(() => { config = new Config() + limiterStub = { + isAllowed: sinon.stub().returns(true) + } + + keepTrace = sinon.stub() + updateRateLimitedMetric = sinon.stub() + DDWAF = sinon.stub() DDWAF.version = sinon.stub().returns('1.2.3') DDWAF.prototype.dispose = sinon.stub() @@ -41,8 +48,19 @@ describe('WAF Manager', () => { WAFManager = proxyquire('../../../src/appsec/waf/waf_manager', { '@datadog/native-appsec': { DDWAF } }) + + const webMock = { + root: sinon.stub().returns({ mock: 'rootSpan' }), + getContext: sinon.stub().returns(webContext) + } + waf = proxyquire('../../../src/appsec/waf', { - './waf_manager': WAFManager + './waf_manager': WAFManager, + '../../rate_limiter': function () { return limiterStub }, + '../../priority_sampler': { keepTrace }, + '../../standalone/product': { ASM: 'ASM' }, + '../../plugins/util/web': webMock, + '../telemetry': { updateRateLimitedMetric } }) waf.destroy() @@ -54,7 +72,6 @@ describe('WAF Manager', () => { sinon.spy(Reporter, 'reportWafConfigUpdate') webContext = {} - sinon.stub(web, 'getContext').returns(webContext) }) afterEach(() => { @@ -122,6 +139,100 @@ describe('WAF Manager', () => { expect(run).to.be.calledOnceWithExactly(payload, undefined) }) + + describe('sampling priority', () => { + let mockWafContext, req + + beforeEach(() => { + req = { mock: 'request' } + mockWafContext = { run: sinon.stub() } + WAFManager.prototype.getWAFContext = sinon.stub().returns(mockWafContext) + waf.init(rules, config.appsec) + }) + + it('should call keepTrace when result.keep is true and rate limiter allows', () => { + const result = { keep: true, events: [] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(true) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(keepTrace).to.have.been.calledOnceWithExactly({ mock: 'rootSpan' }, 'ASM') + expect(updateRateLimitedMetric).not.to.have.been.called + }) + + it('should call updateRateLimitedMetric when result.keep is true but rate limiter denies', () => { + const result = { keep: true, events: [] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(false) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(updateRateLimitedMetric).to.have.been.calledOnceWithExactly(req) + expect(keepTrace).not.to.have.been.called + }) + + it('should not call keepTrace or updateRateLimitedMetric when result.keep is false', () => { + const result = { keep: false, events: [] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(true) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(keepTrace).not.to.have.been.called + expect(updateRateLimitedMetric).not.to.have.been.called + }) + + it('should not call keepTrace or updateRateLimitedMetric when result.keep is undefined', () => { + const result = { events: [] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(true) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(keepTrace).not.to.have.been.called + expect(updateRateLimitedMetric).not.to.have.been.called + }) + + it('should not call keepTrace or updateRateLimitedMetric when result is null', () => { + mockWafContext.run.returns(null) + limiterStub.isAllowed.returns(true) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(keepTrace).not.to.have.been.called + expect(updateRateLimitedMetric).not.to.have.been.called + }) + + it('should handle keep=true with events and rate limiter allowing', () => { + const result = { keep: true, events: ['attack_event'] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(true) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(keepTrace).to.have.been.calledOnceWithExactly({ mock: 'rootSpan' }, 'ASM') + expect(updateRateLimitedMetric).not.to.have.been.called + }) + + it('should handle keep=true with events but rate limiter denying', () => { + const result = { keep: true, events: ['attack_event'] } + mockWafContext.run.returns(result) + limiterStub.isAllowed.returns(false) + + const payload = { persistent: { 'server.io.net.url': 'http://example.com' } } + waf.run(payload, req) + + expect(updateRateLimitedMetric).to.have.been.calledOnceWithExactly(req) + expect(keepTrace).not.to.have.been.called + }) + }) }) describe('waf disabled check', () => { diff --git a/packages/dd-trace/test/remote_config/index.spec.js b/packages/dd-trace/test/remote_config/index.spec.js index f20f06db81a..6d9d75ff83f 100644 --- a/packages/dd-trace/test/remote_config/index.spec.js +++ b/packages/dd-trace/test/remote_config/index.spec.js @@ -250,6 +250,8 @@ describe('Remote Config index', () => { .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_RASP_CMDI, true) expect(rc.updateCapabilities) .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, true) + expect(rc.updateCapabilities) + .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true) expect(rc.setProductHandler).to.have.been.calledWith('ASM_DATA') expect(rc.setProductHandler).to.have.been.calledWith('ASM_DD') @@ -300,6 +302,8 @@ describe('Remote Config index', () => { .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_RASP_CMDI, true) expect(rc.updateCapabilities) .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, true) + expect(rc.updateCapabilities) + .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true) expect(rc.setProductHandler).to.have.been.calledWith('ASM_DATA') expect(rc.setProductHandler).to.have.been.calledWith('ASM_DD') @@ -352,6 +356,8 @@ describe('Remote Config index', () => { .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_RASP_CMDI, true) expect(rc.updateCapabilities) .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, true) + expect(rc.updateCapabilities) + .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true) }) it('should not activate rasp capabilities if rasp is disabled', () => { @@ -387,6 +393,8 @@ describe('Remote Config index', () => { .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, true) expect(rc.updateCapabilities) .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, true) + expect(rc.updateCapabilities) + .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, true) expect(rc.updateCapabilities) .to.not.have.been.calledWith(RemoteConfigCapabilities.ASM_RASP_SSRF) expect(rc.updateCapabilities) @@ -446,6 +454,8 @@ describe('Remote Config index', () => { .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_RASP_CMDI, false) expect(rc.updateCapabilities) .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_DD_MULTICONFIG, false) + expect(rc.updateCapabilities) + .to.have.been.calledWithExactly(RemoteConfigCapabilities.ASM_TRACE_TAGGING_RULES, false) expect(rc.removeProductHandler).to.have.been.calledWith('ASM_DATA') expect(rc.removeProductHandler).to.have.been.calledWith('ASM_DD') diff --git a/yarn.lock b/yarn.lock index b583b268e15..98ecfade6c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -211,10 +211,10 @@ resolved "https://registry.yarnpkg.com/@datadog/libdatadog/-/libdatadog-0.7.0.tgz#81e07d3040c628892db697ccd01ae3c4d2a76315" integrity sha512-VVZLspzQcfEU47gmGCVoRkngn7RgFRR4CHjw4YaX8eWT+xz4Q4l6PvA45b7CMk9nlt3MNN5MtGdYttYMIpo6Sg== -"@datadog/native-appsec@10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-10.0.0.tgz#366d292445c6d4b02782f3c28a2a4f26acd498f3" - integrity sha512-1veYkp5DRy3RnqFRQGGIfX6ON8UibIq6YOXa+oJ0n5TRQFd1v6qWPzfonO31W4rDJ5qjxNRV6lX33m8JfaYnag== +"@datadog/native-appsec@10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-10.0.1.tgz#220bd855971ebe3c517915a6db4caec50545b128" + integrity sha512-v60KOnQOAn6lcrFB8eHXfW5H227mk5tuj0CCqlk1FCZ5UxW8jjvXYV3cVjlQvSkwk55BN9jh6xa99QaX5WkqmQ== dependencies: node-gyp-build "^3.9.0"