From 98ceacfd844cd587107928f71d4a2f0f06c023f3 Mon Sep 17 00:00:00 2001 From: Sam Brenner <106700075+sabrenner@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:42:14 -0500 Subject: [PATCH 1/8] [MLOB-1942] fix(llmobs): auto-annotations for wrapped functions happen after manual annotations (#4960) * auto-annotation done before span finish * error cases * callback scoped consistently to apm * make clearer --- packages/dd-trace/src/llmobs/sdk.js | 116 +++++++++--- .../dd-trace/test/llmobs/sdk/index.spec.js | 177 ++++++++++++++++++ 2 files changed, 267 insertions(+), 26 deletions(-) diff --git a/packages/dd-trace/src/llmobs/sdk.js b/packages/dd-trace/src/llmobs/sdk.js index 91fe1e8f70a..2a6d548d656 100644 --- a/packages/dd-trace/src/llmobs/sdk.js +++ b/packages/dd-trace/src/llmobs/sdk.js @@ -1,12 +1,12 @@ 'use strict' -const { SPAN_KIND, OUTPUT_VALUE } = require('./constants/tags') +const { SPAN_KIND, OUTPUT_VALUE, INPUT_VALUE } = require('./constants/tags') const { getFunctionArguments, validateKind } = require('./util') -const { isTrue } = require('../util') +const { isTrue, isError } = require('../util') const { storage } = require('./storage') @@ -134,29 +134,63 @@ class LLMObs extends NoopLLMObs { function wrapped () { const span = llmobs._tracer.scope().active() - - const result = llmobs._activate(span, { kind, options: llmobsOptions }, () => { - if (!['llm', 'embedding'].includes(kind)) { - llmobs.annotate(span, { inputData: getFunctionArguments(fn, arguments) }) + const fnArgs = arguments + + const lastArgId = fnArgs.length - 1 + const cb = fnArgs[lastArgId] + const hasCallback = typeof cb === 'function' + + if (hasCallback) { + const scopeBoundCb = llmobs._bind(cb) + fnArgs[lastArgId] = function () { + // it is standard practice to follow the callback signature (err, result) + // however, we try to parse the arguments to determine if the first argument is an error + // if it is not, and is not undefined, we will use that for the output value + const maybeError = arguments[0] + const maybeResult = arguments[1] + + llmobs._autoAnnotate( + span, + kind, + getFunctionArguments(fn, fnArgs), + isError(maybeError) || maybeError == null ? maybeResult : maybeError + ) + + return scopeBoundCb.apply(this, arguments) } + } - return fn.apply(this, arguments) - }) + try { + const result = llmobs._activate(span, { kind, options: llmobsOptions }, () => fn.apply(this, fnArgs)) + + if (result && typeof result.then === 'function') { + return result.then( + value => { + if (!hasCallback) { + llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), value) + } + return value + }, + err => { + llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs)) + throw err + } + ) + } - if (result && typeof result.then === 'function') { - return result.then(value => { - if (value && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { - llmobs.annotate(span, { outputData: value }) - } - return value - }) - } + // it is possible to return a value and have a callback + // however, since the span finishes when the callback is called, it is possible that + // the callback is called before the function returns (although unlikely) + // we do not want to throw for "annotating a finished span" in this case + if (!hasCallback) { + llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), result) + } - if (result && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { - llmobs.annotate(span, { outputData: result }) + return result + } catch (e) { + llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs)) + throw e } - - return result } return this._tracer.wrap(name, spanOptions, wrapped) @@ -333,20 +367,34 @@ class LLMObs extends NoopLLMObs { flushCh.publish() } + _autoAnnotate (span, kind, input, output) { + const annotations = {} + if (input && !['llm', 'embedding'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[INPUT_VALUE]) { + annotations.inputData = input + } + + if (output && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { + annotations.outputData = output + } + + this.annotate(span, annotations) + } + _active () { const store = storage.getStore() return store?.span } - _activate (span, { kind, options } = {}, fn) { + _activate (span, options, fn) { const parent = this._active() if (this.enabled) storage.enterWith({ span }) - this._tagger.registerLLMObsSpan(span, { - ...options, - parent, - kind - }) + if (options) { + this._tagger.registerLLMObsSpan(span, { + ...options, + parent + }) + } try { return fn() @@ -355,6 +403,22 @@ class LLMObs extends NoopLLMObs { } } + // bind function to active LLMObs span + _bind (fn) { + if (typeof fn !== 'function') return fn + + const llmobs = this + const activeSpan = llmobs._active() + + const bound = function () { + return llmobs._activate(activeSpan, null, () => { + return fn.apply(this, arguments) + }) + } + + return bound + } + _extractOptions (options) { const { modelName, diff --git a/packages/dd-trace/test/llmobs/sdk/index.spec.js b/packages/dd-trace/test/llmobs/sdk/index.spec.js index 69dad1d60c4..e7cfb81a47d 100644 --- a/packages/dd-trace/test/llmobs/sdk/index.spec.js +++ b/packages/dd-trace/test/llmobs/sdk/index.spec.js @@ -17,6 +17,7 @@ describe('sdk', () => { let LLMObsSDK let llmobs let tracer + let clock before(() => { tracer = require('../../../../dd-trace') @@ -43,6 +44,8 @@ describe('sdk', () => { // remove max listener warnings, we don't care about the writer anyways process.removeAllListeners('beforeExit') + + clock = sinon.useFakeTimers() }) afterEach(() => { @@ -435,6 +438,180 @@ describe('sdk', () => { }) }) + it('does not crash for auto-annotation values that are overriden', () => { + const circular = {} + circular.circular = circular + + let span + function myWorkflow (input) { + span = llmobs._active() + llmobs.annotate({ + inputData: 'circular', + outputData: 'foo' + }) + return '' + } + + const wrappedMyWorkflow = llmobs.wrap({ kind: 'workflow' }, myWorkflow) + wrappedMyWorkflow(circular) + + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'workflow', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': 'circular', + '_ml_obs.meta.output.value': 'foo' + }) + }) + + it('only auto-annotates input on error', () => { + let span + function myTask (foo, bar) { + span = llmobs._active() + throw new Error('error') + } + + const wrappedMyTask = llmobs.wrap({ kind: 'task' }, myTask) + + expect(() => wrappedMyTask('foo', 'bar')).to.throw() + + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'task', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': JSON.stringify({ foo: 'foo', bar: 'bar' }) + }) + }) + + it('only auto-annotates input on error for promises', () => { + let span + function myTask (foo, bar) { + span = llmobs._active() + return Promise.reject(new Error('error')) + } + + const wrappedMyTask = llmobs.wrap({ kind: 'task' }, myTask) + + return wrappedMyTask('foo', 'bar') + .catch(() => { + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'task', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': JSON.stringify({ foo: 'foo', bar: 'bar' }) + }) + }) + }) + + it('auto-annotates the inputs of the callback function as the outputs for the span', () => { + let span + function myWorkflow (input, cb) { + span = llmobs._active() + setTimeout(() => { + cb(null, 'output') + }, 1000) + } + + const wrappedMyWorkflow = llmobs.wrap({ kind: 'workflow' }, myWorkflow) + wrappedMyWorkflow('input', (err, res) => { + expect(err).to.not.exist + expect(res).to.equal('output') + }) + + clock.tick(1000) + + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'workflow', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': JSON.stringify({ input: 'input' }), + '_ml_obs.meta.output.value': 'output' + }) + }) + + it('ignores the error portion of the callback for auto-annotation', () => { + let span + function myWorkflow (input, cb) { + span = llmobs._active() + setTimeout(() => { + cb(new Error('error'), 'output') + }, 1000) + } + + const wrappedMyWorkflow = llmobs.wrap({ kind: 'workflow' }, myWorkflow) + wrappedMyWorkflow('input', (err, res) => { + expect(err).to.exist + expect(res).to.equal('output') + }) + + clock.tick(1000) + + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'workflow', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': JSON.stringify({ input: 'input' }), + '_ml_obs.meta.output.value': 'output' + }) + }) + + it('auto-annotates the first argument of the callback as the output if it is not an error', () => { + let span + function myWorkflow (input, cb) { + span = llmobs._active() + setTimeout(() => { + cb('output', 'ignore') + }, 1000) + } + + const wrappedMyWorkflow = llmobs.wrap({ kind: 'workflow' }, myWorkflow) + wrappedMyWorkflow('input', (res, irrelevant) => { + expect(res).to.equal('output') + expect(irrelevant).to.equal('ignore') + }) + + clock.tick(1000) + + expect(LLMObsTagger.tagMap.get(span)).to.deep.equal({ + '_ml_obs.meta.span.kind': 'workflow', + '_ml_obs.meta.ml_app': 'mlApp', + '_ml_obs.llmobs_parent_id': 'undefined', + '_ml_obs.meta.input.value': JSON.stringify({ input: 'input' }), + '_ml_obs.meta.output.value': 'output' + }) + }) + + it('maintains context consistent with the tracer', () => { + let llmSpan, workflowSpan, taskSpan + + function myLlm (input, cb) { + llmSpan = llmobs._active() + setTimeout(() => { + cb(null, 'output') + }, 1000) + } + const myWrappedLlm = llmobs.wrap({ kind: 'llm' }, myLlm) + + llmobs.trace({ kind: 'workflow', name: 'myWorkflow' }, _workflow => { + workflowSpan = _workflow + tracer.trace('apmOperation', () => { + myWrappedLlm('input', (err, res) => { + expect(err).to.not.exist + expect(res).to.equal('output') + llmobs.trace({ kind: 'task', name: 'afterLlmTask' }, _task => { + taskSpan = _task + + const llmParentId = LLMObsTagger.tagMap.get(llmSpan)['_ml_obs.llmobs_parent_id'] + expect(llmParentId).to.equal(workflowSpan.context().toSpanId()) + + const taskParentId = LLMObsTagger.tagMap.get(taskSpan)['_ml_obs.llmobs_parent_id'] + expect(taskParentId).to.equal(workflowSpan.context().toSpanId()) + }) + }) + }) + }) + }) + // TODO: need span kind optional for this test it.skip('sets the span name to "unnamed-anonymous-function" if no name is provided', () => { let span From 4d6a8e3fe8edee52a9e28796d6138f776cb4a767 Mon Sep 17 00:00:00 2001 From: ishabi Date: Tue, 24 Dec 2024 17:35:20 +0100 Subject: [PATCH 2/8] support aerospike 6 (#5057) --- .github/workflows/plugins.yml | 4 ++++ packages/datadog-instrumentations/src/aerospike.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 4822539ecab..79650e6d473 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -35,6 +35,10 @@ jobs: range: '>=5.12.1' aerospike-image: ce-6.4.0.3 test-image: ubuntu-latest + - node-version: 22 + range: '>=6.0.0' + aerospike-image: ce-6.4.0.3 + test-image: ubuntu-latest runs-on: ${{ matrix.test-image }} services: aerospike: diff --git a/packages/datadog-instrumentations/src/aerospike.js b/packages/datadog-instrumentations/src/aerospike.js index 497a64aaf80..ba310b6e2de 100644 --- a/packages/datadog-instrumentations/src/aerospike.js +++ b/packages/datadog-instrumentations/src/aerospike.js @@ -40,7 +40,7 @@ function wrapProcess (process) { addHook({ name: 'aerospike', file: 'lib/commands/command.js', - versions: ['4', '5'] + versions: ['4', '5', '6'] }, commandFactory => { return shimmer.wrapFunction(commandFactory, f => wrapCreateCommand(f)) From 330e973219497fe3b494a96a7ce11cba719eb3ea Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 2 Jan 2025 10:55:47 +0100 Subject: [PATCH 3/8] [DI] Clean up snapshot integration test (#5050) The comment about the breakpoint line number being hardcoded is no longer true. Since this is no longer the case, this commit removes the hack used to avoid changing the line number when adding new variables to the captured snapshot. --- integration-tests/debugger/snapshot.spec.js | 30 +++++----- .../debugger/target-app/snapshot.js | 59 +++++++++---------- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/integration-tests/debugger/snapshot.spec.js b/integration-tests/debugger/snapshot.spec.js index e3d17b225c4..e2f9d9eb047 100644 --- a/integration-tests/debugger/snapshot.spec.js +++ b/integration-tests/debugger/snapshot.spec.js @@ -16,10 +16,10 @@ describe('Dynamic Instrumentation', function () { assert.deepEqual(Object.keys(captures.lines), [String(t.breakpoint.line)]) const { locals } = captures.lines[t.breakpoint.line] - const { request, fastify, getSomeData } = locals + const { request, fastify, getUndefined } = locals delete locals.request delete locals.fastify - delete locals.getSomeData + delete locals.getUndefined // from block scope assert.deepEqual(locals, { @@ -67,19 +67,19 @@ describe('Dynamic Instrumentation', function () { } }, emptyObj: { type: 'Object', fields: {} }, - fn: { - type: 'Function', - fields: { - length: { type: 'number', value: '0' }, - name: { type: 'string', value: 'fn' } - } - }, p: { type: 'Promise', fields: { '[[PromiseState]]': { type: 'string', value: 'fulfilled' }, '[[PromiseResult]]': { type: 'undefined' } } + }, + arrowFn: { + type: 'Function', + fields: { + length: { type: 'number', value: '0' }, + name: { type: 'string', value: 'arrowFn' } + } } }) @@ -99,11 +99,11 @@ describe('Dynamic Instrumentation', function () { assert.equal(fastify.type, 'Object') assert.typeOf(fastify.fields, 'Object') - assert.deepEqual(getSomeData, { + assert.deepEqual(getUndefined, { type: 'Function', fields: { length: { type: 'number', value: '0' }, - name: { type: 'string', value: 'getSomeData' } + name: { type: 'string', value: 'getUndefined' } } }) @@ -118,7 +118,7 @@ describe('Dynamic Instrumentation', function () { const { locals } = captures.lines[t.breakpoint.line] delete locals.request delete locals.fastify - delete locals.getSomeData + delete locals.getUndefined assert.deepEqual(locals, { nil: { type: 'null', isNull: true }, @@ -139,8 +139,8 @@ describe('Dynamic Instrumentation', function () { arr: { type: 'Array', notCapturedReason: 'depth' }, obj: { type: 'Object', notCapturedReason: 'depth' }, emptyObj: { type: 'Object', notCapturedReason: 'depth' }, - fn: { type: 'Function', notCapturedReason: 'depth' }, - p: { type: 'Promise', notCapturedReason: 'depth' } + p: { type: 'Promise', notCapturedReason: 'depth' }, + arrowFn: { type: 'Function', notCapturedReason: 'depth' } }) done() @@ -212,7 +212,7 @@ describe('Dynamic Instrumentation', function () { // Up to 3 properties from the local scope 'request', 'nil', 'undef', // Up to 3 properties from the closure scope - 'fastify', 'getSomeData' + 'fastify', 'getUndefined' ]) assert.strictEqual(locals.request.type, 'Request') diff --git a/integration-tests/debugger/target-app/snapshot.js b/integration-tests/debugger/target-app/snapshot.js index 03cfc758556..63cc6f3d33b 100644 --- a/integration-tests/debugger/target-app/snapshot.js +++ b/integration-tests/debugger/target-app/snapshot.js @@ -5,12 +5,33 @@ const Fastify = require('fastify') const fastify = Fastify() -// Since line probes have hardcoded line numbers, we want to try and keep the line numbers from changing within the -// `handler` function below when making changes to this file. This is achieved by calling `getSomeData` and keeping all -// variable names on the same line as much as possible. fastify.get('/:name', function handler (request) { - // eslint-disable-next-line no-unused-vars - const { nil, undef, bool, num, bigint, str, lstr, sym, regex, arr, obj, emptyObj, fn, p } = getSomeData() + /* eslint-disable no-unused-vars */ + const nil = null + const undef = getUndefined() + const bool = true + const num = 42 + const bigint = 42n + const str = 'foo' + // eslint-disable-next-line @stylistic/js/max-len + const lstr = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' + const sym = Symbol('foo') + const regex = /bar/i + const arr = [1, 2, 3, 4, 5] + const obj = { + foo: { + baz: 42, + nil: null, + undef: undefined, + deep: { nested: { obj: { that: { goes: { on: { forever: true } } } } } } + }, + bar: true + } + const emptyObj = {} + const p = Promise.resolve() + const arrowFn = () => {} + /* eslint-enable no-unused-vars */ + return { hello: request.params.name } // BREAKPOINT: /foo }) @@ -22,30 +43,4 @@ fastify.listen({ port: process.env.APP_PORT }, (err) => { process.send({ port: process.env.APP_PORT }) }) -function getSomeData () { - return { - nil: null, - undef: undefined, - bool: true, - num: 42, - bigint: 42n, - str: 'foo', - // eslint-disable-next-line @stylistic/js/max-len - lstr: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - sym: Symbol('foo'), - regex: /bar/i, - arr: [1, 2, 3, 4, 5], - obj: { - foo: { - baz: 42, - nil: null, - undef: undefined, - deep: { nested: { obj: { that: { goes: { on: { forever: true } } } } } } - }, - bar: true - }, - emptyObj: {}, - fn: () => {}, - p: Promise.resolve() - } -} +function getUndefined () {} From 8981beb6c71a4a665c6d8da87ca37e9a25fa7919 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 2 Jan 2025 11:02:33 +0100 Subject: [PATCH 4/8] [DI] Add TODO comment (#5054) --- packages/dd-trace/src/debugger/devtools_client/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/dd-trace/src/debugger/devtools_client/index.js b/packages/dd-trace/src/debugger/devtools_client/index.js index 9634003bf61..df158b7d2da 100644 --- a/packages/dd-trace/src/debugger/devtools_client/index.js +++ b/packages/dd-trace/src/debugger/devtools_client/index.js @@ -141,6 +141,8 @@ function highestOrUndefined (num, max) { } async function getDD (callFrameId) { + // TODO: Consider if an `objectGroup` should be used, so it can be explicitly released using + // `Runtime.releaseObjectGroup` const { result } = await session.post('Debugger.evaluateOnCallFrame', { callFrameId, expression, From f813f43d201b3bf552eacfcedfcc85fb0e43c15b Mon Sep 17 00:00:00 2001 From: ishabi Date: Thu, 2 Jan 2025 16:37:48 +0100 Subject: [PATCH 5/8] upgrade mocha@9 to mocha@10 (#5065) --- package.json | 2 +- yarn.lock | 280 +++++++++++++++++++++++++-------------------------- 2 files changed, 137 insertions(+), 145 deletions(-) diff --git a/package.json b/package.json index 9b0abdb34db..3e4582e9438 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "jszip": "^3.5.0", "knex": "^2.4.2", "mkdirp": "^3.0.1", - "mocha": "^9", + "mocha": "^10", "msgpack-lite": "^0.1.26", "multer": "^1.4.5-lts.1", "nock": "^11.3.3", diff --git a/yarn.lock b/yarn.lock index a56218a0a45..fc37d5e7016 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1012,11 +1012,6 @@ resolved "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz" integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw== -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -1063,10 +1058,10 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^4.2.1: version "4.3.2" @@ -1355,6 +1350,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -1362,9 +1364,9 @@ braces@~3.0.2: dependencies: fill-range "^7.1.1" -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== browserslist@^4.21.9: @@ -1533,7 +1535,7 @@ checksum@^1.0.0: dependencies: optimist "~0.3.5" -chokidar@3.5.3, chokidar@^3.3.0: +chokidar@^3.3.0: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -1548,6 +1550,21 @@ chokidar@3.5.3, chokidar@^3.3.0: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" @@ -1818,13 +1835,6 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - debug@4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" @@ -1846,6 +1856,13 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: dependencies: ms "2.1.2" +debug@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -1918,17 +1935,12 @@ detect-newline@^3.0.0: resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity "sha1-V29d/GOuGhkv8ZLYrTr2MImRtlE= sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" -diff@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.1.0: +diff@^5.1.0, diff@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== @@ -2116,11 +2128,6 @@ escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" @@ -2131,6 +2138,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + eslint-compat-utils@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4" @@ -2471,14 +2483,6 @@ find-cache-dir@^3.2.0: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@5.0.0, find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" @@ -2487,6 +2491,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + findit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz" @@ -2674,29 +2686,28 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.1.1" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" globals@^11.1.0: version "11.12.0" @@ -2752,11 +2763,6 @@ graphql@0.13.2: dependencies: iterall "^1.2.1" -growl@1.10.5: - version "1.10.5" - resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - has-async-hooks@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/has-async-hooks/-/has-async-hooks-1.0.0.tgz" @@ -2831,9 +2837,9 @@ hdr-histogram-percentiles-obj@^2.0.0: dependencies: hdr-histogram-js "^1.0.0" -he@1.2.0: +he@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== html-escaper@^2.0.0: @@ -3292,13 +3298,6 @@ jmespath@0.16.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" @@ -3307,6 +3306,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" @@ -3457,7 +3463,7 @@ lodash@^4.17.13, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4: resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@4.1.0: +log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -3560,13 +3566,6 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" @@ -3574,6 +3573,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" @@ -3603,35 +3609,31 @@ mkdirp@^3.0.1: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz" integrity "sha1-5E5MVgf7J5wWgkFxPMbg/qmty1A= sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==" -mocha@^9: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.8" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" +mocha@^10: + version "10.8.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.8.2.tgz#8d8342d016ed411b12a429eb731b825f961afb96" + integrity sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" module-details-from-path@^1.0.3: version "1.0.3" @@ -3653,7 +3655,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1, ms@^2.1.2: +ms@2.1.3, ms@^2.1.1, ms@^2.1.2, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3681,11 +3683,6 @@ multer@^1.4.5-lts.1: type-is "^1.6.4" xtend "^4.0.0" -nanoid@3.3.8: - version "3.3.8" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" @@ -4438,10 +4435,10 @@ send@0.19.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" @@ -4695,18 +4692,11 @@ strip-bom@^4.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-json-comments@3.1.1, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -4721,6 +4711,13 @@ supports-color@^7.1.0, supports-color@^7.2.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" @@ -5142,7 +5139,7 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: gopd "^1.0.1" has-tostringtag "^1.0.2" -which@2.0.2, which@^2.0.1, which@^2.0.2: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -5166,10 +5163,10 @@ wordwrap@~0.0.2: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" integrity sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw== -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== wrap-ansi@^6.2.0: version "6.2.0" @@ -5257,11 +5254,6 @@ yaml@^2.5.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" @@ -5270,14 +5262,14 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@2.0.0: +yargs-unparser@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: camelcase "^6.0.0" @@ -5285,19 +5277,6 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^15.0.2: version "15.4.1" resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" @@ -5315,6 +5294,19 @@ yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" From 12f24185e76af18d18b41a7e53f360ae7de04c8a Mon Sep 17 00:00:00 2001 From: ishabi Date: Thu, 2 Jan 2025 19:28:37 +0100 Subject: [PATCH 6/8] Update native-appsec to 8.4.0 (#5064) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3e4582e9438..fedd38e7312 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ }, "dependencies": { "@datadog/libdatadog": "^0.3.0", - "@datadog/native-appsec": "8.3.0", + "@datadog/native-appsec": "8.4.0", "@datadog/native-iast-rewriter": "2.6.1", "@datadog/native-iast-taint-tracking": "3.2.0", "@datadog/native-metrics": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index fc37d5e7016..4d8e42d2abc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -406,10 +406,10 @@ resolved "https://registry.yarnpkg.com/@datadog/libdatadog/-/libdatadog-0.3.0.tgz#2fc1e2695872840bc8c356f66acf675da428d6f0" integrity sha512-TbP8+WyXfh285T17FnLeLUOPl4SbkRYMqKgcmknID2mXHNrbt5XJgW9bnDgsrrtu31Q7FjWWw2WolgRLWyzLRA== -"@datadog/native-appsec@8.3.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.3.0.tgz#91afd89d18d386be4da8a1b0e04500f2f8b5eb66" - integrity sha512-RYHbSJ/MwJcJaLzaCaZvUyNLUKFbMshayIiv4ckpFpQJDiq1T8t9iM2k7008s75g1vRuXfsRNX7MaLn4aoFuWA== +"@datadog/native-appsec@8.4.0": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.4.0.tgz#5c44d949ff8f40a94c334554db79c1c470653bae" + integrity sha512-LC47AnpVLpQFEUOP/nIIs+i0wLb8XYO+et3ACaJlHa2YJM3asR4KZTqQjDQNy08PTAUbVvYWKwfSR1qVsU/BeA== dependencies: node-gyp-build "^3.9.0" From 86c8e26b6f6e95219d674610a1a8a36217694e5b Mon Sep 17 00:00:00 2001 From: Igor Unanua Date: Tue, 7 Jan 2025 09:03:34 +0100 Subject: [PATCH 7/8] ignore noop spans (#5063) --- packages/dd-trace/src/priority_sampler.js | 6 ++++-- packages/dd-trace/test/priority_sampler.spec.js | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/dd-trace/src/priority_sampler.js b/packages/dd-trace/src/priority_sampler.js index 3a89f71f664..7497f1f919c 100644 --- a/packages/dd-trace/src/priority_sampler.js +++ b/packages/dd-trace/src/priority_sampler.js @@ -120,13 +120,15 @@ class PrioritySampler { if (!span || !this.validate(samplingPriority)) return const context = this._getContext(span) + const root = context._trace.started[0] + + if (!root) return // noop span context._sampling.priority = samplingPriority context._sampling.mechanism = mechanism - const root = context._trace.started[0] - log.trace(span, samplingPriority, mechanism) + this._addDecisionMaker(root) } diff --git a/packages/dd-trace/test/priority_sampler.spec.js b/packages/dd-trace/test/priority_sampler.spec.js index 88c134a5758..2c1a2e273bd 100644 --- a/packages/dd-trace/test/priority_sampler.spec.js +++ b/packages/dd-trace/test/priority_sampler.spec.js @@ -490,6 +490,16 @@ describe('PrioritySampler', () => { expect(context._sampling.mechanism).to.equal(SAMPLING_MECHANISM_APPSEC) expect(context._trace.tags[DECISION_MAKER_KEY]).to.equal('-0') }) + + it('should ignore noop spans', () => { + context._trace.started[0] = undefined // noop + + prioritySampler.setPriority(span, USER_KEEP, SAMPLING_MECHANISM_APPSEC) + + expect(context._sampling.priority).to.undefined + expect(context._sampling.mechanism).to.undefined + expect(context._trace.tags[DECISION_MAKER_KEY]).to.undefined + }) }) describe('keepTrace', () => { From 1e7622373a420c6358bd1509080eb54c7e5dd769 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Tue, 7 Jan 2025 10:51:34 +0100 Subject: [PATCH 8/8] Send tags, including git metadata, to RC endpoint (#5070) In requests to the RC endpoint, add dd tags, including dd tags containing git metadata. --- .../src/appsec/remote_config/manager.js | 12 +++++++++++- .../test/appsec/remote_config/manager.spec.js | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/dd-trace/src/appsec/remote_config/manager.js b/packages/dd-trace/src/appsec/remote_config/manager.js index 75c72690503..19ed709b27f 100644 --- a/packages/dd-trace/src/appsec/remote_config/manager.js +++ b/packages/dd-trace/src/appsec/remote_config/manager.js @@ -9,6 +9,7 @@ const log = require('../../log') const { getExtraServices } = require('../../service-naming/extra-services') const { UNACKNOWLEDGED, ACKNOWLEDGED, ERROR } = require('./apply_states') const Scheduler = require('./scheduler') +const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../../plugins/util/tags') const clientId = uuid() @@ -33,6 +34,14 @@ class RemoteConfigManager extends EventEmitter { port: config.port })) + const tags = config.repositoryUrl + ? { + ...config.tags, + [GIT_REPOSITORY_URL]: config.repositoryUrl, + [GIT_COMMIT_SHA]: config.commitSHA + } + : config.tags + this._handlers = new Map() const appliedConfigs = this.appliedConfigs = new Map() @@ -67,7 +76,8 @@ class RemoteConfigManager extends EventEmitter { service: config.service, env: config.env, app_version: config.version, - extra_services: [] + extra_services: [], + tags: Object.entries(tags).map((pair) => pair.join(':')) }, capabilities: DEFAULT_CAPABILITY // updated by `updateCapabilities()` }, diff --git a/packages/dd-trace/test/appsec/remote_config/manager.spec.js b/packages/dd-trace/test/appsec/remote_config/manager.spec.js index 2a32e834e06..8d0c82d0dc9 100644 --- a/packages/dd-trace/test/appsec/remote_config/manager.spec.js +++ b/packages/dd-trace/test/appsec/remote_config/manager.spec.js @@ -98,7 +98,8 @@ describe('RemoteConfigManager', () => { service: config.service, env: config.env, app_version: config.version, - extra_services: [] + extra_services: [], + tags: ['runtime-id:runtimeId'] }, capabilities: 'AA==' }, @@ -108,6 +109,20 @@ describe('RemoteConfigManager', () => { expect(rc.appliedConfigs).to.be.an.instanceOf(Map) }) + it('should add git metadata to tags if present', () => { + const configWithGit = { + ...config, + repositoryUrl: 'https://github.com/DataDog/dd-trace-js', + commitSHA: '1234567890' + } + const rc = new RemoteConfigManager(configWithGit) + expect(rc.state.client.client_tracer.tags).to.deep.equal([ + 'runtime-id:runtimeId', + 'git.repository_url:https://github.com/DataDog/dd-trace-js', + 'git.commit.sha:1234567890' + ]) + }) + describe('updateCapabilities', () => { it('should set multiple capabilities to true', () => { rc.updateCapabilities(Capabilities.ASM_ACTIVATION, true)