Comparing version 6.0.0-pre-09455e6 to 6.0.0-pre-0f36e48
{ | ||
"name": "dd-trace", | ||
"version": "6.0.0-pre-09455e6", | ||
"version": "6.0.0-pre-0f36e48", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -39,2 +39,3 @@ "main": "index.js", | ||
"test:integration:playwright": "mocha --colors --timeout 30000 \"integration-tests/playwright/*.spec.js\"", | ||
"test:integration:selenium": "mocha --colors --timeout 30000 \"integration-tests/selenium/*.spec.js\"", | ||
"test:integration:profiler": "mocha --colors --timeout 90000 \"integration-tests/profiler/*.spec.js\"", | ||
@@ -73,7 +74,7 @@ "test:integration:serverless": "mocha --colors --timeout 30000 \"integration-tests/serverless/*.spec.js\"", | ||
"dependencies": { | ||
"@datadog/native-appsec": "7.1.0", | ||
"@datadog/native-appsec": "7.1.1", | ||
"@datadog/native-iast-rewriter": "2.3.0", | ||
"@datadog/native-iast-taint-tracking": "1.7.0", | ||
"@datadog/native-metrics": "^2.0.0", | ||
"@datadog/pprof": "5.1.0", | ||
"@datadog/pprof": "5.2.0", | ||
"@datadog/sketches-js": "^2.1.0", | ||
@@ -100,3 +101,3 @@ "@opentelemetry/api": "^1.0.0", | ||
"path-to-regexp": "^0.1.2", | ||
"pprof-format": "^2.0.7", | ||
"pprof-format": "^2.1.0", | ||
"protobufjs": "^7.2.5", | ||
@@ -103,0 +104,0 @@ "retry": "^0.13.1", |
'use strict' | ||
const shimmer = require('../../datadog-shimmer') | ||
const { channel } = require('./helpers/instrument') | ||
const { tracingChannel } = require('dc-polyfill') | ||
const { createWrapFetch } = require('./helpers/fetch') | ||
const startChannel = channel('apm:fetch:request:start') | ||
const finishChannel = channel('apm:fetch:request:finish') | ||
const errorChannel = channel('apm:fetch:request:error') | ||
if (globalThis.fetch) { | ||
const ch = tracingChannel('apm:fetch:request') | ||
const wrapFetch = createWrapFetch(globalThis.Request, ch) | ||
function wrapFetch (fetch, Request) { | ||
if (typeof fetch !== 'function') return fetch | ||
return function (input, init) { | ||
if (!startChannel.hasSubscribers) return fetch.apply(this, arguments) | ||
const req = new Request(input, init) | ||
const headers = req.headers | ||
const message = { req, headers } | ||
return startChannel.runStores(message, () => { | ||
// Request object is read-only so we need new objects to change headers. | ||
arguments[0] = message.req | ||
arguments[1] = { headers: message.headers } | ||
return fetch.apply(this, arguments) | ||
.then( | ||
res => { | ||
message.res = res | ||
finishChannel.publish(message) | ||
return res | ||
}, | ||
err => { | ||
if (err.name !== 'AbortError') { | ||
message.error = err | ||
errorChannel.publish(message) | ||
} | ||
finishChannel.publish(message) | ||
throw err | ||
} | ||
) | ||
}) | ||
} | ||
globalThis.fetch = shimmer.wrap(fetch, wrapFetch(fetch)) | ||
} | ||
if (globalThis.fetch) { | ||
globalThis.fetch = shimmer.wrap(fetch, wrapFetch(fetch, globalThis.Request)) | ||
} |
@@ -61,2 +61,3 @@ 'use strict' | ||
'jest-jasmine2': () => require('../jest'), | ||
'jest-runtime': () => require('../jest'), | ||
'jest-worker': () => require('../jest'), | ||
@@ -107,4 +108,5 @@ knex: () => require('../knex'), | ||
router: () => require('../router'), | ||
'selenium-webdriver': () => require('../selenium'), | ||
sequelize: () => require('../sequelize'), | ||
sharedb: () => require('../sharedb'), | ||
sequelize: () => require('../sequelize'), | ||
tedious: () => require('../tedious'), | ||
@@ -111,0 +113,0 @@ when: () => require('../when'), |
@@ -14,3 +14,4 @@ 'use strict' | ||
addEfdStringToTestName, | ||
removeEfdStringFromTestName | ||
removeEfdStringFromTestName, | ||
getIsFaultyEarlyFlakeDetection | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -48,2 +49,5 @@ const { | ||
// Message sent by jest's main process to workers to run a test suite (=test file) | ||
// https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/types.ts#L37 | ||
const CHILD_MESSAGE_CALL = 1 | ||
// Maximum time we'll wait for the tracer to flush | ||
@@ -53,3 +57,3 @@ const FLUSH_TIMEOUT = 10000 | ||
let skippableSuites = [] | ||
let knownTests = [] | ||
let knownTests = {} | ||
let isCodeCoverageEnabled = false | ||
@@ -64,2 +68,4 @@ let isSuitesSkippingEnabled = false | ||
let earlyFlakeDetectionNumRetries = 0 | ||
let earlyFlakeDetectionFaultyThreshold = 30 | ||
let isEarlyFlakeDetectionFaulty = false | ||
let hasFilteredSkippableSuites = false | ||
@@ -80,2 +86,3 @@ | ||
const retriedTestsToNumAttempts = new Map() | ||
const newTestsTestStatuses = new Map() | ||
@@ -109,2 +116,9 @@ // based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41 | ||
function getEfdStats (testStatuses) { | ||
return testStatuses.reduce((acc, testStatus) => { | ||
acc[testStatus]++ | ||
return acc | ||
}, { pass: 0, fail: 0 }) | ||
} | ||
function getWrappedEnvironment (BaseEnvironment, jestVersion) { | ||
@@ -119,2 +133,3 @@ return class DatadogEnvironment extends BaseEnvironment { | ||
this.global._ddtrace = global._ddtrace | ||
this.hasSnapshotTests = undefined | ||
@@ -133,5 +148,8 @@ this.displayName = config.projectConfig?.displayName?.name | ||
if (this.isEarlyFlakeDetectionEnabled) { | ||
const hasKnownTests = !!knownTests.jest | ||
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries | ||
try { | ||
this.knownTestsForThisSuite = this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests) | ||
this.knownTestsForThisSuite = hasKnownTests | ||
? (knownTests.jest[this.testSuite] || []) | ||
: this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests) | ||
} catch (e) { | ||
@@ -144,2 +162,17 @@ // If there has been an error parsing the tests, we'll disable Early Flake Deteciton | ||
getHasSnapshotTests () { | ||
if (this.hasSnapshotTests !== undefined) { | ||
return this.hasSnapshotTests | ||
} | ||
let hasSnapshotTests = true | ||
try { | ||
const { _snapshotData } = this.context.expect.getState().snapshotState | ||
hasSnapshotTests = Object.keys(_snapshotData).length > 0 | ||
} catch (e) { | ||
// if we can't be sure, we'll err on the side of caution and assume it has snapshots | ||
} | ||
this.hasSnapshotTests = hasSnapshotTests | ||
return hasSnapshotTests | ||
} | ||
// Function that receives a list of known tests for a test service and | ||
@@ -157,3 +190,3 @@ // returns the ones that belong to the current suite | ||
} | ||
return knownTestsForSuite.jest?.[this.testSuite] || [] | ||
return knownTestsForSuite | ||
} | ||
@@ -230,2 +263,9 @@ | ||
retriedTestsToNumAttempts.set(testName, 0) | ||
// Retrying snapshots has proven to be problematic, so we'll skip them for now | ||
// We'll still detect new tests, but we won't retry them. | ||
// TODO: do not bail out of EFD with the whole test suite | ||
if (this.getHasSnapshotTests()) { | ||
log.warn('Early flake detection is disabled for suites with snapshots') | ||
return | ||
} | ||
for (let retryIndex = 0; retryIndex < earlyFlakeDetectionNumRetries; retryIndex++) { | ||
@@ -256,2 +296,15 @@ if (this.global.test) { | ||
event.test.fn = originalTestFns.get(event.test) | ||
// We'll store the test statuses of the retries | ||
if (this.isEarlyFlakeDetectionEnabled) { | ||
const testName = getJestTestName(event.test) | ||
const originalTestName = removeEfdStringFromTestName(testName) | ||
const isNewTest = retriedTestsToNumAttempts.has(originalTestName) | ||
if (isNewTest) { | ||
if (newTestsTestStatuses.has(originalTestName)) { | ||
newTestsTestStatuses.get(originalTestName).push(status) | ||
} else { | ||
newTestsTestStatuses.set(originalTestName, [status]) | ||
} | ||
} | ||
} | ||
}) | ||
@@ -300,3 +353,3 @@ } | ||
itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion }) | ||
skippableSuites = [] | ||
return jestSuitesToRun.suitesToRun | ||
@@ -399,2 +452,3 @@ } | ||
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries | ||
earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold | ||
} | ||
@@ -514,2 +568,3 @@ } catch (err) { | ||
isEarlyFlakeDetectionEnabled, | ||
isEarlyFlakeDetectionFaulty, | ||
onDone | ||
@@ -526,2 +581,24 @@ }) | ||
/** | ||
* If Early Flake Detection (EFD) is enabled the logic is as follows: | ||
* - If all attempts for a test are failing, the test has failed and we will let the test process fail. | ||
* - If just a single attempt passes, we will prevent the test process from failing. | ||
* The rationale behind is the following: you may still be able to block your CI pipeline by gating | ||
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too. | ||
*/ | ||
if (isEarlyFlakeDetectionEnabled) { | ||
let numFailedTestsToIgnore = 0 | ||
for (const testStatuses of newTestsTestStatuses.values()) { | ||
const { pass, fail } = getEfdStats(testStatuses) | ||
if (pass > 0) { // as long as one passes, we'll consider the test passed | ||
numFailedTestsToIgnore += fail | ||
} | ||
} | ||
// If every test that failed was an EFD retry, we'll consider the suite passed | ||
if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) { | ||
result.results.success = true | ||
} | ||
} | ||
return result | ||
@@ -638,3 +715,2 @@ }) | ||
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled | ||
config.testEnvironmentOptions._ddKnownTests = knownTests | ||
}) | ||
@@ -732,9 +808,22 @@ | ||
shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () { | ||
if (!isSuitesSkippingEnabled || !skippableSuites.length) { | ||
return getTestPaths.apply(this, arguments) | ||
const testPaths = await getTestPaths.apply(this, arguments) | ||
const [{ rootDir, shard }] = arguments | ||
if (isEarlyFlakeDetectionEnabled) { | ||
const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir)) | ||
const isFaulty = | ||
getIsFaultyEarlyFlakeDetection(projectSuites, knownTests.jest || {}, earlyFlakeDetectionFaultyThreshold) | ||
if (isFaulty) { | ||
log.error('Early flake detection is disabled because the number of new suites is too high.') | ||
isEarlyFlakeDetectionEnabled = false | ||
const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions | ||
// Project config is shared among all tests, so we can modify it here | ||
if (testEnvironmentOptions) { | ||
testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false | ||
} | ||
isEarlyFlakeDetectionFaulty = true | ||
} | ||
} | ||
const [{ rootDir, shard }] = arguments | ||
if (shard?.shardCount > 1) { | ||
if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) { | ||
// If the user is using jest sharding, we want to apply the filtering of tests in the shard process. | ||
@@ -747,6 +836,4 @@ // The reason for this is the following: | ||
// causing the shards to potentially run the same suite. | ||
return getTestPaths.apply(this, arguments) | ||
return testPaths | ||
} | ||
const testPaths = await getTestPaths.apply(this, arguments) | ||
const { tests } = testPaths | ||
@@ -811,3 +898,31 @@ | ||
const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = [ | ||
'selenium-webdriver' | ||
] | ||
function shouldBypassJestRequireEngine (moduleName) { | ||
return ( | ||
LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.some(library => moduleName.includes(library)) | ||
) | ||
} | ||
addHook({ | ||
name: 'jest-runtime', | ||
versions: ['>=24.8.0'] | ||
}, (runtimePackage) => { | ||
const Runtime = runtimePackage.default ? runtimePackage.default : runtimePackage | ||
shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) { | ||
// TODO: do this for every library that we instrument | ||
if (shouldBypassJestRequireEngine(moduleName)) { | ||
// To bypass jest's own require engine | ||
return this._requireCoreModule(moduleName) | ||
} | ||
return requireModuleOrMock.apply(this, arguments) | ||
}) | ||
return runtimePackage | ||
}) | ||
addHook({ | ||
name: 'jest-worker', | ||
@@ -818,2 +933,34 @@ versions: ['>=24.9.0'], | ||
const ChildProcessWorker = childProcessWorker.default | ||
shimmer.wrap(ChildProcessWorker.prototype, 'send', send => function (request) { | ||
if (!isEarlyFlakeDetectionEnabled) { | ||
return send.apply(this, arguments) | ||
} | ||
const [type] = request | ||
// eslint-disable-next-line | ||
// https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/workers/ChildProcessWorker.ts#L424 | ||
if (type === CHILD_MESSAGE_CALL) { | ||
// This is the message that the main process sends to the worker to run a test suite (=test file). | ||
// In here we modify the config.testEnvironmentOptions to include the known tests for the suite. | ||
// This way the suite only knows about the tests that are part of it. | ||
const args = request[request.length - 1] | ||
if (args.length > 1) { | ||
return send.apply(this, arguments) | ||
} | ||
if (!args[0]?.config) { | ||
return send.apply(this, arguments) | ||
} | ||
const [{ globalConfig, config, path: testSuiteAbsolutePath }] = args | ||
const testSuite = getTestSuitePath(testSuiteAbsolutePath, globalConfig.rootDir || process.cwd()) | ||
const suiteKnownTests = knownTests.jest?.[testSuite] || [] | ||
args[0].config = { | ||
...config, | ||
testEnvironmentOptions: { | ||
...config.testEnvironmentOptions, | ||
_ddKnownTests: suiteKnownTests | ||
} | ||
} | ||
} | ||
return send.apply(this, arguments) | ||
}) | ||
shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', _onMessage => function () { | ||
@@ -820,0 +967,0 @@ const [code, data] = arguments[0] |
@@ -71,3 +71,6 @@ 'use strict' | ||
result.then( | ||
innerAsyncResource.bind(() => producerFinishCh.publish(undefined)), | ||
innerAsyncResource.bind(res => { | ||
producerFinishCh.publish(undefined) | ||
producerCommitCh.publish(res) | ||
}), | ||
innerAsyncResource.bind(err => { | ||
@@ -81,8 +84,2 @@ if (err) { | ||
result.then(res => { | ||
if (producerCommitCh.hasSubscribers) { | ||
producerCommitCh.publish(res) | ||
} | ||
}) | ||
return result | ||
@@ -89,0 +86,0 @@ } catch (e) { |
@@ -24,3 +24,4 @@ 'use strict' | ||
}, mongoose => { | ||
if (mongoose.Promise !== global.Promise) { | ||
// As of Mongoose 7, custom promise libraries are no longer supported and mongoose.Promise may be undefined | ||
if (mongoose.Promise && mongoose.Promise !== global.Promise) { | ||
shimmer.wrap(mongoose.Promise.prototype, 'then', wrapThen) | ||
@@ -27,0 +28,0 @@ } |
@@ -13,2 +13,94 @@ 'use strict' | ||
const V4_PACKAGE_SHIMS = [ | ||
{ | ||
file: 'resources/chat/completions.js', | ||
targetClass: 'Completions', | ||
baseResource: 'chat.completions', | ||
methods: ['create'] | ||
}, | ||
{ | ||
file: 'resources/completions.js', | ||
targetClass: 'Completions', | ||
baseResource: 'completions', | ||
methods: ['create'] | ||
}, | ||
{ | ||
file: 'resources/embeddings.js', | ||
targetClass: 'Embeddings', | ||
baseResource: 'embeddings', | ||
methods: ['create'] | ||
}, | ||
{ | ||
file: 'resources/files.js', | ||
targetClass: 'Files', | ||
baseResource: 'files', | ||
methods: ['create', 'del', 'list', 'retrieve'] | ||
}, | ||
{ | ||
file: 'resources/files.js', | ||
targetClass: 'Files', | ||
baseResource: 'files', | ||
methods: ['retrieveContent'], | ||
versions: ['>=4.0.0 <4.17.1'] | ||
}, | ||
{ | ||
file: 'resources/files.js', | ||
targetClass: 'Files', | ||
baseResource: 'files', | ||
methods: ['content'], // replaced `retrieveContent` in v4.17.1 | ||
versions: ['>=4.17.1'] | ||
}, | ||
{ | ||
file: 'resources/images.js', | ||
targetClass: 'Images', | ||
baseResource: 'images', | ||
methods: ['createVariation', 'edit', 'generate'] | ||
}, | ||
{ | ||
file: 'resources/fine-tuning/jobs/jobs.js', | ||
targetClass: 'Jobs', | ||
baseResource: 'fine_tuning.jobs', | ||
methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'], | ||
versions: ['>=4.34.0'] // file location changed in 4.34.0 | ||
}, | ||
{ | ||
file: 'resources/fine-tuning/jobs.js', | ||
targetClass: 'Jobs', | ||
baseResource: 'fine_tuning.jobs', | ||
methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'], | ||
versions: ['>=4.1.0 <4.34.0'] | ||
}, | ||
{ | ||
file: 'resources/fine-tunes.js', // deprecated after 4.1.0 | ||
targetClass: 'FineTunes', | ||
baseResource: 'fine-tune', | ||
methods: ['cancel', 'create', 'list', 'listEvents', 'retrieve'], | ||
versions: ['>=4.0.0 <4.1.0'] | ||
}, | ||
{ | ||
file: 'resources/models.js', | ||
targetClass: 'Models', | ||
baseResource: 'models', | ||
methods: ['del', 'list', 'retrieve'] | ||
}, | ||
{ | ||
file: 'resources/moderations.js', | ||
targetClass: 'Moderations', | ||
baseResource: 'moderations', | ||
methods: ['create'] | ||
}, | ||
{ | ||
file: 'resources/audio/transcriptions.js', | ||
targetClass: 'Transcriptions', | ||
baseResource: 'audio.transcriptions', | ||
methods: ['create'] | ||
}, | ||
{ | ||
file: 'resources/audio/translations.js', | ||
targetClass: 'Translations', | ||
baseResource: 'audio.translations', | ||
methods: ['create'] | ||
} | ||
] | ||
addHook({ name: 'openai', file: 'dist/api.js', versions: ['>=3.0.0 <4'] }, exports => { | ||
@@ -52,1 +144,58 @@ const methodNames = Object.getOwnPropertyNames(exports.OpenAIApi.prototype) | ||
}) | ||
for (const shim of V4_PACKAGE_SHIMS) { | ||
const { file, targetClass, baseResource, methods } = shim | ||
addHook({ name: 'openai', file, versions: shim.versions || ['>=4'] }, exports => { | ||
const targetPrototype = exports[targetClass].prototype | ||
for (const methodName of methods) { | ||
shimmer.wrap(targetPrototype, methodName, methodFn => function () { | ||
if (!startCh.hasSubscribers) { | ||
return methodFn.apply(this, arguments) | ||
} | ||
const client = this._client || this.client | ||
startCh.publish({ | ||
methodName: `${baseResource}.${methodName}`, | ||
args: arguments, | ||
basePath: client.baseURL, | ||
apiKey: client.apiKey | ||
}) | ||
const apiProm = methodFn.apply(this, arguments) | ||
// wrapping `parse` avoids problematic wrapping of `then` when trying to call | ||
// `withResponse` in userland code after. This way, we can return the whole `APIPromise` | ||
shimmer.wrap(apiProm, 'parse', origApiPromParse => function () { | ||
return origApiPromParse.apply(this, arguments) | ||
// the original response is wrapped in a promise, so we need to unwrap it | ||
.then(body => Promise.all([this.responsePromise, body])) | ||
.then(([{ response, options }, body]) => { | ||
finishCh.publish({ | ||
headers: response.headers, | ||
body, | ||
path: response.url, | ||
method: options.method | ||
}) | ||
return body | ||
}) | ||
.catch(err => { | ||
errorCh.publish({ err }) | ||
throw err | ||
}) | ||
.finally(() => { | ||
// maybe we don't want to unwrap here in case the promise is re-used? | ||
// other hand: we want to avoid resource leakage | ||
shimmer.unwrap(apiProm, 'parse') | ||
}) | ||
}) | ||
return apiProm | ||
}) | ||
} | ||
return exports | ||
}) | ||
} |
@@ -24,3 +24,3 @@ 'use strict' | ||
addHook({ name: 'oracledb', versions: ['5'] }, oracledb => { | ||
addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => { | ||
shimmer.wrap(oracledb.Connection.prototype, 'execute', execute => { | ||
@@ -27,0 +27,0 @@ return function wrappedExecute (dbQuery, ...args) { |
@@ -7,3 +7,8 @@ 'use strict' | ||
if (process.env.DD_TRACE_OTEL_ENABLED) { | ||
const otelSdkEnabled = process.env.DD_TRACE_OTEL_ENABLED || | ||
process.env.OTEL_SDK_DISABLED | ||
? !process.env.OTEL_SDK_DISABLED | ||
: undefined | ||
if (otelSdkEnabled) { | ||
addHook({ | ||
@@ -10,0 +15,0 @@ name: '@opentelemetry/sdk-trace-node', |
@@ -19,3 +19,3 @@ 'use strict' | ||
TEST_SOURCE_FILE, | ||
TEST_EARLY_FLAKE_IS_ENABLED, | ||
TEST_EARLY_FLAKE_ENABLED, | ||
TEST_IS_NEW, | ||
@@ -72,3 +72,3 @@ TEST_IS_RETRY | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true') | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
@@ -75,0 +75,0 @@ |
@@ -31,3 +31,3 @@ const { | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED | ||
TEST_EARLY_FLAKE_ENABLED | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -368,3 +368,3 @@ const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util') | ||
if (this.isEarlyFlakeDetectionEnabled) { | ||
testSessionSpanMetadata[TEST_EARLY_FLAKE_IS_ENABLED] = 'true' | ||
testSessionSpanMetadata[TEST_EARLY_FLAKE_ENABLED] = 'true' | ||
} | ||
@@ -371,0 +371,0 @@ |
@@ -7,2 +7,12 @@ /* eslint-disable */ | ||
// If the test is using multi domain with cy.origin, trying to access | ||
// window properties will result in a cross origin error. | ||
function safeGetRum (window) { | ||
try { | ||
return window.DD_RUM | ||
} catch (e) { | ||
return null | ||
} | ||
} | ||
function isNewTest (test) { | ||
@@ -66,3 +76,3 @@ return !knownTestsForSuite.includes(test.fullTitle()) | ||
cy.window().then(win => { | ||
if (win.DD_RUM) { | ||
if (safeGetRum(win)) { | ||
win.dispatchEvent(new Event('beforeunload')) | ||
@@ -89,7 +99,13 @@ } | ||
if (win.DD_RUM) { | ||
if (safeGetRum(win)) { | ||
testInfo.isRUMActive = true | ||
} | ||
cy.task('dd:afterEach', { test: testInfo, coverage: win.__coverage__ }) | ||
let coverage | ||
try { | ||
coverage = win.__coverage__ | ||
} catch (e) { | ||
// ignore error and continue | ||
} | ||
cy.task('dd:afterEach', { test: testInfo, coverage }) | ||
}) | ||
}) |
@@ -7,10 +7,6 @@ 'use strict' | ||
static get id () { return 'fetch' } | ||
static get prefix () { return 'apm:fetch:request' } | ||
static get prefix () { return 'tracing:apm:fetch:request' } | ||
addTraceSub (eventName, handler) { | ||
this.addSub(`apm:${this.constructor.id}:${this.operation}:${eventName}`, handler) | ||
} | ||
bindStart (message) { | ||
const req = message.req | ||
bindStart (ctx) { | ||
const req = ctx.req | ||
const options = new URL(req.url) | ||
@@ -21,13 +17,26 @@ const headers = options.headers = Object.fromEntries(req.headers.entries()) | ||
message.args = { options } | ||
ctx.args = { options } | ||
const store = super.bindStart(message) | ||
const store = super.bindStart(ctx) | ||
message.headers = headers | ||
message.req = new globalThis.Request(req, { headers }) | ||
for (const name in headers) { | ||
if (!req.headers.has(name)) { | ||
req.headers.set(name, headers[name]) | ||
} | ||
} | ||
return store | ||
} | ||
error (ctx) { | ||
if (ctx.error.name === 'AbortError') return | ||
return super.error(ctx) | ||
} | ||
asyncEnd (ctx) { | ||
ctx.res = ctx.result | ||
return this.finish(ctx) | ||
} | ||
} | ||
module.exports = FetchPlugin |
@@ -21,3 +21,4 @@ const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin') | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED, | ||
TEST_EARLY_FLAKE_ENABLED, | ||
TEST_EARLY_FLAKE_ABORT_REASON, | ||
JEST_DISPLAY_NAME | ||
@@ -93,2 +94,3 @@ } = require('../../dd-trace/src/plugins/util/test') | ||
isEarlyFlakeDetectionEnabled, | ||
isEarlyFlakeDetectionFaulty, | ||
onDone | ||
@@ -120,4 +122,7 @@ }) => { | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true') | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
if (isEarlyFlakeDetectionFaulty) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'faulty') | ||
} | ||
@@ -124,0 +129,0 @@ this.testModuleSpan.finish() |
@@ -23,3 +23,3 @@ 'use strict' | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED | ||
TEST_EARLY_FLAKE_ENABLED | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -148,6 +148,5 @@ const { COMPONENT } = require('../../dd-trace/src/constants') | ||
const store = storage.getStore() | ||
const span = store?.span | ||
if (store && store.span) { | ||
const span = store.span | ||
if (span) { | ||
span.setTag(TEST_STATUS, status) | ||
@@ -228,3 +227,3 @@ | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true') | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
@@ -231,0 +230,0 @@ |
@@ -87,3 +87,3 @@ 'use strict' | ||
// createChatCompletion, createCompletion, createImage, createImageEdit, createTranscription, createTranslation | ||
if ('prompt' in payload) { | ||
if (payload.prompt) { | ||
const prompt = payload.prompt | ||
@@ -103,3 +103,3 @@ store.prompt = prompt | ||
// createEdit, createEmbedding, createModeration | ||
if ('input' in payload) { | ||
if (payload.input) { | ||
const normalized = normalizeStringOrTokenArray(payload.input, false) | ||
@@ -119,2 +119,4 @@ tags['openai.request.input'] = truncateText(normalized) | ||
case 'createFineTune': | ||
case 'fine_tuning.jobs.create': | ||
case 'fine-tune.create': | ||
createFineTuneRequestExtraction(tags, payload) | ||
@@ -124,4 +126,7 @@ break | ||
case 'createImage': | ||
case 'images.generate': | ||
case 'createImageEdit': | ||
case 'images.edit': | ||
case 'createImageVariation': | ||
case 'images.createVariation': | ||
commonCreateImageRequestExtraction(tags, payload, store) | ||
@@ -131,2 +136,3 @@ break | ||
case 'createChatCompletion': | ||
case 'chat.completions.create': | ||
createChatCompletionRequestExtraction(tags, payload, store) | ||
@@ -136,3 +142,5 @@ break | ||
case 'createFile': | ||
case 'files.create': | ||
case 'retrieveFile': | ||
case 'files.retrieve': | ||
commonFileRequestExtraction(tags, payload) | ||
@@ -142,3 +150,5 @@ break | ||
case 'createTranscription': | ||
case 'audio.transcriptions.create': | ||
case 'createTranslation': | ||
case 'audio.translations.create': | ||
commonCreateAudioRequestExtraction(tags, payload, store) | ||
@@ -148,2 +158,3 @@ break | ||
case 'retrieveModel': | ||
case 'models.retrieve': | ||
retrieveModelRequestExtraction(tags, payload) | ||
@@ -153,5 +164,12 @@ break | ||
case 'listFineTuneEvents': | ||
case 'fine_tuning.jobs.listEvents': | ||
case 'fine-tune.listEvents': | ||
case 'retrieveFineTune': | ||
case 'fine_tuning.jobs.retrieve': | ||
case 'fine-tune.retrieve': | ||
case 'deleteModel': | ||
case 'models.del': | ||
case 'cancelFineTune': | ||
case 'fine_tuning.jobs.cancel': | ||
case 'fine-tune.cancel': | ||
commonLookupFineTuneRequestExtraction(tags, payload) | ||
@@ -161,2 +179,3 @@ break | ||
case 'createEdit': | ||
case 'edits.create': | ||
createEditRequestExtraction(tags, payload, store) | ||
@@ -170,2 +189,6 @@ break | ||
finish ({ headers, body, method, path }) { | ||
if (headers.constructor.name === 'Headers') { | ||
headers = Object.fromEntries(headers) | ||
} | ||
const span = this.activeSpan | ||
@@ -179,2 +202,7 @@ const methodName = span._spanContext._tags['resource.name'] | ||
if (path.startsWith('https://') || path.startsWith('http://')) { | ||
// basic checking for if the path was set as a full URL | ||
// not using a full regex as it will likely be "https://api.openai.com/..." | ||
path = new URL(path).pathname | ||
} | ||
const endpoint = lookupOperationEndpoint(methodName, path) | ||
@@ -184,3 +212,3 @@ | ||
'openai.request.endpoint': endpoint, | ||
'openai.request.method': method, | ||
'openai.request.method': method.toUpperCase(), | ||
@@ -236,3 +264,3 @@ 'openai.organization.id': body.organization_id, // only available in fine-tunes endpoints | ||
if (body && ('usage' in body)) { | ||
if (body && body.usage) { | ||
const promptTokens = body.usage.prompt_tokens | ||
@@ -245,15 +273,15 @@ const completionTokens = body.usage.completion_tokens | ||
if ('x-ratelimit-limit-requests' in headers) { | ||
if (headers['x-ratelimit-limit-requests']) { | ||
this.metrics.gauge('openai.ratelimit.requests', Number(headers['x-ratelimit-limit-requests']), tags) | ||
} | ||
if ('x-ratelimit-remaining-requests' in headers) { | ||
if (headers['x-ratelimit-remaining-requests']) { | ||
this.metrics.gauge('openai.ratelimit.remaining.requests', Number(headers['x-ratelimit-remaining-requests']), tags) | ||
} | ||
if ('x-ratelimit-limit-tokens' in headers) { | ||
if (headers['x-ratelimit-limit-tokens']) { | ||
this.metrics.gauge('openai.ratelimit.tokens', Number(headers['x-ratelimit-limit-tokens']), tags) | ||
} | ||
if ('x-ratelimit-remaining-tokens' in headers) { | ||
if (headers['x-ratelimit-remaining-tokens']) { | ||
this.metrics.gauge('openai.ratelimit.remaining.tokens', Number(headers['x-ratelimit-remaining-tokens']), tags) | ||
@@ -293,6 +321,6 @@ } | ||
const message = payload.messages[i] | ||
tags[`openai.request.${i}.content`] = truncateText(message.content) | ||
tags[`openai.request.${i}.role`] = message.role | ||
tags[`openai.request.${i}.name`] = message.name | ||
tags[`openai.request.${i}.finish_reason`] = message.finish_reason | ||
tags[`openai.request.messages.${i}.content`] = truncateText(message.content) | ||
tags[`openai.request.messages.${i}.role`] = message.role | ||
tags[`openai.request.messages.${i}.name`] = message.name | ||
tags[`openai.request.messages.${i}.finish_reason`] = message.finish_reason | ||
} | ||
@@ -303,4 +331,5 @@ } | ||
// createImageEdit, createImageVariation | ||
if (payload.file && typeof payload.file === 'object' && payload.file.path) { | ||
const file = path.basename(payload.file.path) | ||
const img = payload.file || payload.image | ||
if (img && typeof img === 'object' && img.path) { | ||
const file = path.basename(img.path) | ||
tags['openai.request.image'] = file | ||
@@ -325,2 +354,3 @@ store.file = file | ||
case 'createModeration': | ||
case 'moderations.create': | ||
createModerationResponseExtraction(tags, body) | ||
@@ -330,4 +360,7 @@ break | ||
case 'createCompletion': | ||
case 'completions.create': | ||
case 'createChatCompletion': | ||
case 'chat.completions.create': | ||
case 'createEdit': | ||
case 'edits.create': | ||
commonCreateResponseExtraction(tags, body, store) | ||
@@ -337,4 +370,9 @@ break | ||
case 'listFiles': | ||
case 'files.list': | ||
case 'listFineTunes': | ||
case 'fine_tuning.jobs.list': | ||
case 'fine-tune.list': | ||
case 'listFineTuneEvents': | ||
case 'fine_tuning.jobs.listEvents': | ||
case 'fine-tune.listEvents': | ||
commonListCountResponseExtraction(tags, body) | ||
@@ -344,2 +382,3 @@ break | ||
case 'createEmbedding': | ||
case 'embeddings.create': | ||
createEmbeddingResponseExtraction(tags, body) | ||
@@ -349,3 +388,5 @@ break | ||
case 'createFile': | ||
case 'files.create': | ||
case 'retrieveFile': | ||
case 'files.retrieve': | ||
createRetrieveFileResponseExtraction(tags, body) | ||
@@ -355,2 +396,3 @@ break | ||
case 'deleteFile': | ||
case 'files.del': | ||
deleteFileResponseExtraction(tags, body) | ||
@@ -360,2 +402,4 @@ break | ||
case 'downloadFile': | ||
case 'files.retrieveContent': | ||
case 'files.content': | ||
downloadFileResponseExtraction(tags, body) | ||
@@ -365,4 +409,10 @@ break | ||
case 'createFineTune': | ||
case 'fine_tuning.jobs.create': | ||
case 'fine-tune.create': | ||
case 'retrieveFineTune': | ||
case 'fine_tuning.jobs.retrieve': | ||
case 'fine-tune.retrieve': | ||
case 'cancelFineTune': | ||
case 'fine_tuning.jobs.cancel': | ||
case 'fine-tune.cancel': | ||
commonFineTuneResponseExtraction(tags, body) | ||
@@ -372,3 +422,5 @@ break | ||
case 'createTranscription': | ||
case 'audio.transcriptions.create': | ||
case 'createTranslation': | ||
case 'audio.translations.create': | ||
createAudioResponseExtraction(tags, body) | ||
@@ -378,4 +430,7 @@ break | ||
case 'createImage': | ||
case 'images.generate': | ||
case 'createImageEdit': | ||
case 'images.edit': | ||
case 'createImageVariation': | ||
case 'images.createVariation': | ||
commonImageResponseExtraction(tags, body) | ||
@@ -385,2 +440,3 @@ break | ||
case 'listModels': | ||
case 'models.list': | ||
listModelsResponseExtraction(tags, body) | ||
@@ -390,2 +446,3 @@ break | ||
case 'retrieveModel': | ||
case 'models.retrieve': | ||
retrieveModelResponseExtraction(tags, body) | ||
@@ -463,11 +520,15 @@ break | ||
tags['openai.response.fine_tuned_model'] = body.fine_tuned_model | ||
if (body.hyperparams) { | ||
tags['openai.response.hyperparams.n_epochs'] = body.hyperparams.n_epochs | ||
tags['openai.response.hyperparams.batch_size'] = body.hyperparams.batch_size | ||
tags['openai.response.hyperparams.prompt_loss_weight'] = body.hyperparams.prompt_loss_weight | ||
tags['openai.response.hyperparams.learning_rate_multiplier'] = body.hyperparams.learning_rate_multiplier | ||
const hyperparams = body.hyperparams || body.hyperparameters | ||
const hyperparamsKey = body.hyperparams ? 'hyperparams' : 'hyperparameters' | ||
if (hyperparams) { | ||
tags[`openai.response.${hyperparamsKey}.n_epochs`] = hyperparams.n_epochs | ||
tags[`openai.response.${hyperparamsKey}.batch_size`] = hyperparams.batch_size | ||
tags[`openai.response.${hyperparamsKey}.prompt_loss_weight`] = hyperparams.prompt_loss_weight | ||
tags[`openai.response.${hyperparamsKey}.learning_rate_multiplier`] = hyperparams.learning_rate_multiplier | ||
} | ||
tags['openai.response.training_files_count'] = defensiveArrayLength(body.training_files) | ||
tags['openai.response.training_files_count'] = defensiveArrayLength(body.training_files || body.training_file) | ||
tags['openai.response.result_files_count'] = defensiveArrayLength(body.result_files) | ||
tags['openai.response.validation_files_count'] = defensiveArrayLength(body.validation_files) | ||
tags['openai.response.validation_files_count'] = defensiveArrayLength(body.validation_files || body.validation_file) | ||
tags['openai.response.updated_at'] = body.updated_at | ||
@@ -561,14 +622,27 @@ tags['openai.response.status'] = body.status | ||
for (let i = 0; i < body.choices.length; i++) { | ||
const choice = body.choices[i] | ||
tags[`openai.response.choices.${i}.finish_reason`] = choice.finish_reason | ||
tags[`openai.response.choices.${i}.logprobs`] = ('logprobs' in choice) ? 'returned' : undefined | ||
tags[`openai.response.choices.${i}.text`] = truncateText(choice.text) | ||
for (let choiceIdx = 0; choiceIdx < body.choices.length; choiceIdx++) { | ||
const choice = body.choices[choiceIdx] | ||
// logprobs can be nullm and we still want to tag it as 'returned' even when set to 'null' | ||
const specifiesLogProb = Object.keys(choice).indexOf('logprobs') !== -1 | ||
tags[`openai.response.choices.${choiceIdx}.finish_reason`] = choice.finish_reason | ||
tags[`openai.response.choices.${choiceIdx}.logprobs`] = specifiesLogProb ? 'returned' : undefined | ||
tags[`openai.response.choices.${choiceIdx}.text`] = truncateText(choice.text) | ||
// createChatCompletion only | ||
if ('message' in choice) { | ||
if (choice.message) { | ||
const message = choice.message | ||
tags[`openai.response.choices.${i}.message.role`] = message.role | ||
tags[`openai.response.choices.${i}.message.content`] = truncateText(message.content) | ||
tags[`openai.response.choices.${i}.message.name`] = truncateText(message.name) | ||
tags[`openai.response.choices.${choiceIdx}.message.role`] = message.role | ||
tags[`openai.response.choices.${choiceIdx}.message.content`] = truncateText(message.content) | ||
tags[`openai.response.choices.${choiceIdx}.message.name`] = truncateText(message.name) | ||
if (message.tool_calls) { | ||
const toolCalls = message.tool_calls | ||
for (let toolIdx = 0; toolIdx < toolCalls.length; toolIdx++) { | ||
tags[`openai.response.choices.${choiceIdx}.message.tool_calls.${toolIdx}.name`] = | ||
toolCalls[toolIdx].function.name | ||
tags[`openai.response.choices.${choiceIdx}.message.tool_calls.${toolIdx}.arguments`] = | ||
toolCalls[toolIdx].function.arguments | ||
} | ||
} | ||
} | ||
@@ -611,6 +685,19 @@ } | ||
case 'downloadFile': | ||
case 'files.retrieveContent': | ||
case 'files.content': | ||
return { file: body } | ||
} | ||
return typeof body === 'object' ? body : {} | ||
const type = typeof body | ||
if (type === 'string') { | ||
try { | ||
return JSON.parse(body) | ||
} catch { | ||
return body | ||
} | ||
} else if (type === 'object') { | ||
return body | ||
} else { | ||
return {} | ||
} | ||
} | ||
@@ -622,20 +709,35 @@ | ||
case 'deleteModel': | ||
case 'models.del': | ||
case 'retrieveModel': | ||
case 'models.retrieve': | ||
return '/v1/models/*' | ||
case 'deleteFile': | ||
case 'files.del': | ||
case 'retrieveFile': | ||
case 'files.retrieve': | ||
return '/v1/files/*' | ||
case 'downloadFile': | ||
case 'files.retrieveContent': | ||
case 'files.content': | ||
return '/v1/files/*/content' | ||
case 'retrieveFineTune': | ||
case 'fine-tune.retrieve': | ||
return '/v1/fine-tunes/*' | ||
case 'fine_tuning.jobs.retrieve': | ||
return '/v1/fine_tuning/jobs/*' | ||
case 'listFineTuneEvents': | ||
case 'fine-tune.listEvents': | ||
return '/v1/fine-tunes/*/events' | ||
case 'fine_tuning.jobs.listEvents': | ||
return '/v1/fine_tuning/jobs/*/events' | ||
case 'cancelFineTune': | ||
case 'fine-tune.cancel': | ||
return '/v1/fine-tunes/*/cancel' | ||
case 'fine_tuning.jobs.cancel': | ||
return '/v1/fine_tuning/jobs/*/cancel' | ||
} | ||
@@ -654,4 +756,8 @@ | ||
case 'listModels': | ||
case 'models.list': | ||
case 'listFiles': | ||
case 'files.list': | ||
case 'listFineTunes': | ||
case 'fine_tuning.jobs.list': | ||
case 'fine-tune.list': | ||
// no argument | ||
@@ -661,2 +767,3 @@ return {} | ||
case 'retrieveModel': | ||
case 'models.retrieve': | ||
return { id: args[0] } | ||
@@ -671,7 +778,13 @@ | ||
case 'deleteFile': | ||
case 'files.del': | ||
case 'retrieveFile': | ||
case 'files.retrieve': | ||
case 'downloadFile': | ||
case 'files.retrieveContent': | ||
case 'files.content': | ||
return { file_id: args[0] } | ||
case 'listFineTuneEvents': | ||
case 'fine_tuning.jobs.listEvents': | ||
case 'fine-tune.listEvents': | ||
return { | ||
@@ -683,4 +796,9 @@ fine_tune_id: args[0], | ||
case 'retrieveFineTune': | ||
case 'fine_tuning.jobs.retrieve': | ||
case 'fine-tune.retrieve': | ||
case 'deleteModel': | ||
case 'models.del': | ||
case 'cancelFineTune': | ||
case 'fine_tuning.jobs.cancel': | ||
case 'fine-tune.cancel': | ||
return { fine_tune_id: args[0] } | ||
@@ -742,5 +860,14 @@ | ||
function defensiveArrayLength (maybeArray) { | ||
return Array.isArray(maybeArray) ? maybeArray.length : undefined | ||
if (maybeArray) { | ||
if (Array.isArray(maybeArray)) { | ||
return maybeArray.length | ||
} else { | ||
// case of a singular item (ie body.training_file vs body.training_files) | ||
return 1 | ||
} | ||
} | ||
return undefined | ||
} | ||
module.exports = OpenApiPlugin |
'use strict' | ||
const { DogStatsDClient, NoopDogStatsDClient } = require('../../dd-trace/src/dogstatsd') | ||
const { DogStatsDClient } = require('../../dd-trace/src/dogstatsd') | ||
const NoopDogStatsDClient = require('../../dd-trace/src/noop/dogstatsd') | ||
const { ExternalLogger, NoopExternalLogger } = require('../../dd-trace/src/external-logger/src') | ||
@@ -5,0 +6,0 @@ |
@@ -17,3 +17,3 @@ 'use strict' | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED | ||
TEST_EARLY_FLAKE_ENABLED | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -45,3 +45,3 @@ const { RESOURCE_NAME } = require('../../../ext/tags') | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true') | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
@@ -48,0 +48,0 @@ |
@@ -5,2 +5,3 @@ 'use strict' | ||
COMMAND_INJECTION_ANALYZER: require('./command-injection-analyzer'), | ||
HARCODED_PASSWORD_ANALYZER: require('./hardcoded-password-analyzer'), | ||
HARCODED_SECRET_ANALYZER: require('./hardcoded-secret-analyzer'), | ||
@@ -7,0 +8,0 @@ HEADER_INJECTION_ANALYZER: require('./header-injection-analyzer'), |
'use strict' | ||
const Analyzer = require('./vulnerability-analyzer') | ||
const { HARDCODED_SECRET } = require('../vulnerabilities') | ||
const { getRelativePath } = require('../path-line') | ||
const HardcodedBaseAnalyzer = require('./hardcoded-base-analyzer') | ||
const { ValueOnly } = require('./hardcoded-rule-type') | ||
const secretRules = require('./hardcoded-secrets-rules') | ||
const allRules = require('./hardcoded-secret-rules') | ||
class HardcodedSecretAnalyzer extends Analyzer { | ||
class HardcodedSecretAnalyzer extends HardcodedBaseAnalyzer { | ||
constructor () { | ||
super(HARDCODED_SECRET) | ||
super(HARDCODED_SECRET, allRules, allRules.filter(rule => rule.type === ValueOnly)) | ||
} | ||
onConfigure () { | ||
this.addSub('datadog:secrets:result', (secrets) => { this.analyze(secrets) }) | ||
} | ||
analyze (secrets) { | ||
if (!secrets?.file || !secrets.literals) return | ||
const matches = secrets.literals | ||
.filter(literal => literal.value && literal.locations?.length) | ||
.map(literal => { | ||
const match = secretRules.find(rule => literal.value.match(rule.regex)) | ||
return match ? { locations: literal.locations, ruleId: match.id } : undefined | ||
}) | ||
.filter(match => !!match) | ||
if (matches.length) { | ||
const file = getRelativePath(secrets.file) | ||
matches.forEach(match => { | ||
match.locations | ||
.filter(location => location.line) | ||
.forEach(location => this._report({ | ||
file, | ||
line: location.line, | ||
column: location.column, | ||
data: match.ruleId | ||
})) | ||
}) | ||
} | ||
} | ||
_getEvidence (value) { | ||
return { value: `${value.data}` } | ||
} | ||
_getLocation (value) { | ||
return { | ||
path: value.file, | ||
line: value.line, | ||
column: value.column, | ||
isInternal: false | ||
} | ||
} | ||
} | ||
module.exports = new HardcodedSecretAnalyzer() |
/* eslint-disable max-len */ | ||
'use strict' | ||
const { ValueOnly, NameAndValue } = require('./hardcoded-rule-type') | ||
module.exports = [ | ||
{ | ||
id: 'adafruit-api-key', | ||
regex: /(?:adafruit)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9_-]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'adobe-client-id', | ||
regex: /(?:adobe)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'adobe-client-secret', | ||
regex: /\b((p8e-)[a-z0-9]{32})(?:['"\s\x60;]|$)/i | ||
regex: /\b((p8e-)[a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'age-secret-key', | ||
regex: /AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}/ | ||
regex: /AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'airtable-api-key', | ||
regex: /(?:airtable)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{17})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'algolia-api-key', | ||
regex: /(?:algolia)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'alibaba-access-key-id', | ||
regex: /\b((LTAI)[a-z0-9]{20})(?:['"\s\x60;]|$)/i | ||
regex: /\b((LTAI)[a-z0-9]{20})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'asana-client-id', | ||
regex: /(?:asana)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9]{16})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'asana-client-secret', | ||
regex: /(?:asana)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'atlassian-api-token', | ||
regex: /(?:atlassian|confluence|jira)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{24})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'authress-service-client-access-key', | ||
regex: /\b((?:sc|ext|scauth|authress)_[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.acc[_-][a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})(?:['"\s\x60;]|$)/i | ||
regex: /\b((?:sc|ext|scauth|authress)_[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.acc[_-][a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'aws-access-token', | ||
regex: /\b((A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16})(?:['"\s\x60;]|$)/ | ||
regex: /\b((A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16})(?:['"\s\x60;]|$)/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'beamer-api-token', | ||
regex: /(?:beamer)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(b_[a-z0-9=_-]{44})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'bitbucket-client-id', | ||
regex: /(?:bitbucket)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'bitbucket-client-secret', | ||
regex: /(?:bitbucket)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'bittrex-access-key', | ||
regex: /(?:bittrex)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'clojars-api-token', | ||
regex: /(CLOJARS_)[a-z0-9]{60}/i | ||
regex: /(CLOJARS_)[a-z0-9]{60}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'codecov-access-token', | ||
regex: /(?:codecov)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'coinbase-access-token', | ||
regex: /(?:coinbase)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9_-]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'confluent-access-token', | ||
regex: /(?:confluent)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{16})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'confluent-secret-key', | ||
regex: /(?:confluent)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'contentful-delivery-api-token', | ||
regex: /(?:contentful)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{43})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'databricks-api-token', | ||
regex: /\b(dapi[a-h0-9]{32})(?:['"\s\x60;]|$)/i | ||
regex: /\b(dapi[a-h0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'datadog-access-token', | ||
regex: /(?:datadog)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'defined-networking-api-token', | ||
regex: /(?:dnkey)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(dnkey-[a-z0-9=_-]{26}-[a-z0-9=_-]{52})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'digitalocean-access-token', | ||
regex: /\b(doo_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(doo_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'digitalocean-pat', | ||
regex: /\b(dop_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(dop_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'digitalocean-refresh-token', | ||
regex: /\b(dor_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(dor_v1_[a-f0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'discord-api-token', | ||
regex: /(?:discord)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'discord-client-id', | ||
regex: /(?:discord)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9]{18})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'discord-client-secret', | ||
regex: /(?:discord)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'doppler-api-token', | ||
regex: /(dp\.pt\.)[a-z0-9]{43}/i | ||
regex: /(dp\.pt\.)[a-z0-9]{43}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'droneci-access-token', | ||
regex: /(?:droneci)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'dropbox-api-token', | ||
regex: /(?:dropbox)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{15})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'dropbox-long-lived-api-token', | ||
regex: /(?:dropbox)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'dropbox-short-lived-api-token', | ||
regex: /(?:dropbox)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(sl\.[a-z0-9\-=_]{135})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'duffel-api-token', | ||
regex: /duffel_(test|live)_[a-z0-9_\-=]{43}/i | ||
regex: /duffel_(test|live)_[a-z0-9_\-=]{43}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'dynatrace-api-token', | ||
regex: /dt0c01\.[a-z0-9]{24}\.[a-z0-9]{64}/i | ||
regex: /dt0c01\.[a-z0-9]{24}\.[a-z0-9]{64}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'easypost-api-token', | ||
regex: /\bEZAK[a-z0-9]{54}/i | ||
regex: /\bEZAK[a-z0-9]{54}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'etsy-access-token', | ||
regex: /(?:etsy)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{24})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'facebook', | ||
regex: /(?:facebook)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'fastly-api-token', | ||
regex: /(?:fastly)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'finicity-api-token', | ||
regex: /(?:finicity)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'finicity-client-secret', | ||
regex: /(?:finicity)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{20})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'finnhub-access-token', | ||
regex: /(?:finnhub)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{20})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'flickr-access-token', | ||
regex: /(?:flickr)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'flutterwave-public-key', | ||
regex: /FLWPUBK_TEST-[a-h0-9]{32}-X/i | ||
regex: /FLWPUBK_TEST-[a-h0-9]{32}-X/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'frameio-api-token', | ||
regex: /fio-u-[a-z0-9\-_=]{64}/i | ||
regex: /fio-u-[a-z0-9\-_=]{64}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'freshbooks-access-token', | ||
regex: /(?:freshbooks)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'gcp-api-key', | ||
regex: /\b(AIza[0-9a-z\-_]{35})(?:['"\s\x60;]|$)/i | ||
regex: /\b(AIza[0-9a-z\-_]{35})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'github-app-token', | ||
regex: /(ghu|ghs)_[0-9a-zA-Z]{36}/ | ||
regex: /(ghu|ghs)_[0-9a-zA-Z]{36}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'github-fine-grained-pat', | ||
regex: /github_pat_[0-9a-zA-Z_]{82}/ | ||
regex: /github_pat_[0-9a-zA-Z_]{82}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'github-oauth', | ||
regex: /gho_[0-9a-zA-Z]{36}/ | ||
regex: /gho_[0-9a-zA-Z]{36}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'github-pat', | ||
regex: /ghp_[0-9a-zA-Z]{36}/ | ||
regex: /ghp_[0-9a-zA-Z]{36}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'gitlab-pat', | ||
regex: /glpat-[0-9a-zA-Z\-_]{20}/ | ||
regex: /glpat-[0-9a-zA-Z\-_]{20}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'gitlab-ptt', | ||
regex: /glptt-[0-9a-f]{40}/ | ||
regex: /glptt-[0-9a-f]{40}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'gitlab-rrt', | ||
regex: /GR1348941[0-9a-zA-Z\-_]{20}/ | ||
regex: /GR1348941[0-9a-zA-Z\-_]{20}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'gitter-access-token', | ||
regex: /(?:gitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9_-]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'gocardless-api-token', | ||
regex: /(?:gocardless)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(live_[a-z0-9\-_=]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'grafana-api-key', | ||
regex: /\b(eyJrIjoi[a-z0-9]{70,400}={0,2})(?:['"\s\x60;]|$)/i | ||
regex: /\b(eyJrIjoi[a-z0-9]{70,400}={0,2})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'grafana-cloud-api-token', | ||
regex: /\b(glc_[a-z0-9+/]{32,400}={0,2})(?:['"\s\x60;]|$)/i | ||
regex: /\b(glc_[a-z0-9+/]{32,400}={0,2})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'grafana-service-account-token', | ||
regex: /\b(glsa_[a-z0-9]{32}_[a-f0-9]{8})(?:['"\s\x60;]|$)/i | ||
regex: /\b(glsa_[a-z0-9]{32}_[a-f0-9]{8})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'hashicorp-tf-api-token', | ||
regex: /[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}/i | ||
regex: /[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'heroku-api-key', | ||
regex: /(?:heroku)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'hubspot-api-key', | ||
regex: /(?:hubspot)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'intercom-api-key', | ||
regex: /(?:intercom)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{60})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'jfrog-api-key', | ||
regex: /(?:jfrog|artifactory|bintray|xray)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{73})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'jwt', | ||
regex: /\b(ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9/_-]{17,}\.(?:[a-zA-Z0-9/_-]{10,}={0,2})?)(?:['"\s\x60;]|$)/ | ||
regex: /\b(ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9/_-]{17,}\.(?:[a-zA-Z0-9/_-]{10,}={0,2})?)(?:['"\s\x60;]|$)/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'kraken-access-token', | ||
regex: /(?:kraken)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9/=_+-]{80,90})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'kucoin-access-token', | ||
regex: /(?:kucoin)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{24})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'launchdarkly-access-token', | ||
regex: /(?:launchdarkly)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'linear-api-key', | ||
regex: /lin_api_[a-z0-9]{40}/i | ||
regex: /lin_api_[a-z0-9]{40}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'linkedin-client-secret', | ||
regex: /(?:linkedin|linked-in)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{16})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'lob-pub-api-key', | ||
regex: /(?:lob)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}((test|live)_pub_[a-f0-9]{31})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mailchimp-api-key', | ||
regex: /(?:mailchimp)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{32}-us20)(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mailgun-private-api-token', | ||
regex: /(?:mailgun)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(key-[a-f0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mailgun-pub-key', | ||
regex: /(?:mailgun)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(pubkey-[a-f0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mailgun-signing-key', | ||
regex: /(?:mailgun)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mapbox-api-token', | ||
regex: /(?:mapbox)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'mattermost-access-token', | ||
regex: /(?:mattermost)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{26})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'messagebird-api-token', | ||
regex: /(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{25})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'netlify-access-token', | ||
regex: /(?:netlify)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{40,46})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'new-relic-browser-api-token', | ||
regex: /(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(NRJS-[a-f0-9]{19})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'new-relic-user-api-id', | ||
regex: /(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'new-relic-user-api-key', | ||
regex: /(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(NRAK-[a-z0-9]{27})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'npm-access-token', | ||
regex: /\b(npm_[a-z0-9]{36})(?:['"\s\x60;]|$)/i | ||
regex: /\b(npm_[a-z0-9]{36})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'nytimes-access-token', | ||
regex: /(?:nytimes|new-york-times,|newyorktimes)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'okta-access-token', | ||
regex: /(?:okta)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9=_-]{42})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'openai-api-key', | ||
regex: /\b(sk-[a-z0-9]{20}T3BlbkFJ[a-z0-9]{20})(?:['"\s\x60;]|$)/i | ||
regex: /\b(sk-[a-z0-9]{20}T3BlbkFJ[a-z0-9]{20})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'plaid-api-token', | ||
regex: /(?:plaid)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(access-(?:sandbox|development|production)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'plaid-client-id', | ||
regex: /(?:plaid)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{24})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'plaid-secret-key', | ||
regex: /(?:plaid)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{30})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'planetscale-api-token', | ||
regex: /\b(pscale_tkn_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(pscale_tkn_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'planetscale-oauth-token', | ||
regex: /\b(pscale_oauth_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(pscale_oauth_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'planetscale-password', | ||
regex: /\b(pscale_pw_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i | ||
regex: /\b(pscale_pw_[a-z0-9=\-_.]{32,64})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'postman-api-token', | ||
regex: /\b(PMAK-[a-f0-9]{24}-[a-f0-9]{34})(?:['"\s\x60;]|$)/i | ||
regex: /\b(PMAK-[a-f0-9]{24}-[a-f0-9]{34})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'prefect-api-token', | ||
regex: /\b(pnu_[a-z0-9]{36})(?:['"\s\x60;]|$)/i | ||
regex: /\b(pnu_[a-z0-9]{36})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'private-key', | ||
regex: /-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY( BLOCK)?-----[\s\S]*KEY( BLOCK)?----/i | ||
regex: /-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY( BLOCK)?-----[\s\S]*KEY( BLOCK)?----/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'pulumi-api-token', | ||
regex: /\b(pul-[a-f0-9]{40})(?:['"\s\x60;]|$)/i | ||
regex: /\b(pul-[a-f0-9]{40})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'pypi-upload-token', | ||
regex: /pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}/ | ||
regex: /pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'rapidapi-access-token', | ||
regex: /(?:rapidapi)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9_-]{50})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'readme-api-token', | ||
regex: /\b(rdme_[a-z0-9]{70})(?:['"\s\x60;]|$)/i | ||
regex: /\b(rdme_[a-z0-9]{70})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'rubygems-api-token', | ||
regex: /\b(rubygems_[a-f0-9]{48})(?:['"\s\x60;]|$)/i | ||
regex: /\b(rubygems_[a-f0-9]{48})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'scalingo-api-token', | ||
regex: /tk-us-[a-zA-Z0-9-_]{48}/ | ||
regex: /tk-us-[a-zA-Z0-9-_]{48}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'sendbird-access-id', | ||
regex: /(?:sendbird)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'sendbird-access-token', | ||
regex: /(?:sendbird)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'sendgrid-api-token', | ||
regex: /\b(SG\.[a-z0-9=_\-.]{66})(?:['"\s\x60;]|$)/i | ||
regex: /\b(SG\.[a-z0-9=_\-.]{66})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'sendinblue-api-token', | ||
regex: /\b(xkeysib-[a-f0-9]{64}-[a-z0-9]{16})(?:['"\s\x60;]|$)/i | ||
regex: /\b(xkeysib-[a-f0-9]{64}-[a-z0-9]{16})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'sentry-access-token', | ||
regex: /(?:sentry)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'shippo-api-token', | ||
regex: /\b(shippo_(live|test)_[a-f0-9]{40})(?:['"\s\x60;]|$)/i | ||
regex: /\b(shippo_(live|test)_[a-f0-9]{40})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'shopify-access-token', | ||
regex: /shpat_[a-fA-F0-9]{32}/ | ||
regex: /shpat_[a-fA-F0-9]{32}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'shopify-custom-access-token', | ||
regex: /shpca_[a-fA-F0-9]{32}/ | ||
regex: /shpca_[a-fA-F0-9]{32}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'shopify-private-app-access-token', | ||
regex: /shppa_[a-fA-F0-9]{32}/ | ||
regex: /shppa_[a-fA-F0-9]{32}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'shopify-shared-secret', | ||
regex: /shpss_[a-fA-F0-9]{32}/ | ||
regex: /shpss_[a-fA-F0-9]{32}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'sidekiq-secret', | ||
regex: /(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'slack-app-token', | ||
regex: /(xapp-\d-[A-Z0-9]+-\d+-[a-z0-9]+)/i | ||
regex: /(xapp-\d-[A-Z0-9]+-\d+-[a-z0-9]+)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-bot-token', | ||
regex: /(xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)/ | ||
regex: /(xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*)/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-config-access-token', | ||
regex: /(xoxe.xox[bp]-\d-[A-Z0-9]{163,166})/i | ||
regex: /(xoxe.xox[bp]-\d-[A-Z0-9]{163,166})/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-config-refresh-token', | ||
regex: /(xoxe-\d-[A-Z0-9]{146})/i | ||
regex: /(xoxe-\d-[A-Z0-9]{146})/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-legacy-bot-token', | ||
regex: /(xoxb-[0-9]{8,14}-[a-zA-Z0-9]{18,26})/ | ||
regex: /(xoxb-[0-9]{8,14}-[a-zA-Z0-9]{18,26})/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-legacy-token', | ||
regex: /(xox[os]-\d+-\d+-\d+-[a-fA-F\d]+)/ | ||
regex: /(xox[os]-\d+-\d+-\d+-[a-fA-F\d]+)/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-legacy-workspace-token', | ||
regex: /(xox[ar]-(?:\d-)?[0-9a-zA-Z]{8,48})/ | ||
regex: /(xox[ar]-(?:\d-)?[0-9a-zA-Z]{8,48})/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-user-token', | ||
regex: /(xox[pe](?:-[0-9]{10,13}){3}-[a-zA-Z0-9-]{28,34})/ | ||
regex: /(xox[pe](?:-[0-9]{10,13}){3}-[a-zA-Z0-9-]{28,34})/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'slack-webhook-url', | ||
regex: /(https?:\/\/)?hooks.slack.com\/(services|workflows)\/[A-Za-z0-9+/]{43,46}/ | ||
regex: /(https?:\/\/)?hooks.slack.com\/(services|workflows)\/[A-Za-z0-9+/]{43,46}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'snyk-api-token', | ||
regex: /(?:snyk)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'square-access-token', | ||
regex: /\b(sq0atp-[0-9a-z\-_]{22})(?:['"\s\x60;]|$)/i | ||
regex: /\b(sq0atp-[0-9a-z\-_]{22})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'square-secret', | ||
regex: /\b(sq0csp-[0-9a-z\-_]{43})(?:['"\s\x60;]|$)/i | ||
regex: /\b(sq0csp-[0-9a-z\-_]{43})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'squarespace-access-token', | ||
regex: /(?:squarespace)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'stripe-access-token', | ||
regex: /(sk|pk)_(test|live)_[0-9a-z]{10,32}/i | ||
regex: /(sk|pk)_(test|live)_[0-9a-z]{10,32}/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'sumologic-access-token', | ||
regex: /(?:sumo)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{64})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'telegram-bot-api-token', | ||
regex: /(?:^|[^0-9])([0-9]{5,16}:A[a-z0-9_-]{34})(?:$|[^a-z0-9_-])/i | ||
regex: /(?:^|[^0-9])([0-9]{5,16}:A[a-z0-9_-]{34})(?:$|[^a-z0-9_-])/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'travisci-access-token', | ||
regex: /(?:travis)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{22})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'trello-access-token', | ||
regex: /(?:trello)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z-0-9]{32})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twilio-api-key', | ||
regex: /SK[0-9a-fA-F]{32}/ | ||
regex: /SK[0-9a-fA-F]{32}/, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'twitch-api-token', | ||
regex: /(?:twitch)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{30})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twitter-access-secret', | ||
regex: /(?:twitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{45})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twitter-access-token', | ||
regex: /(?:twitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([0-9]{15,25}-[a-z0-9]{20,40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twitter-api-key', | ||
regex: /(?:twitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{25})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twitter-api-secret', | ||
regex: /(?:twitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{50})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'twitter-bearer-token', | ||
regex: /(?:twitter)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(A{22}[a-z0-9%]{80,100})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'typeform-api-token', | ||
regex: /(?:typeform)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(tfp_[a-z0-9\-_.=]{59})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'vault-batch-token', | ||
regex: /\b(hvb\.[a-z0-9_-]{138,212})(?:['"\s\x60;]|$)/i | ||
regex: /\b(hvb\.[a-z0-9_-]{138,212})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'vault-service-token', | ||
regex: /\b(hvs\.[a-z0-9_-]{90,100})(?:['"\s\x60;]|$)/i | ||
regex: /\b(hvs\.[a-z0-9_-]{90,100})(?:['"\s\x60;]|$)/i, | ||
type: ValueOnly | ||
}, | ||
{ | ||
id: 'yandex-access-token', | ||
regex: /(?:yandex)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'yandex-api-key', | ||
regex: /(?:yandex)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(AQVN[a-z0-9_-]{35,38})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'yandex-aws-access-token', | ||
regex: /(?:yandex)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}(YC[a-z0-9_-]{38})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
}, | ||
{ | ||
id: 'zendesk-secret-key', | ||
regex: /(?:zendesk)(?:[0-9a-z\-_\t.]{0,20})(?:[\s|']|[\s|""]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|""|\s|=|\x60){0,5}([a-z0-9]{40})(?:['"\s\x60;]|$)/i, | ||
type: NameAndValue | ||
} | ||
] |
@@ -23,7 +23,11 @@ 'use strict' | ||
'sqreen/lib/package-reader/index.js', | ||
'ws/lib/websocket-server.js' | ||
'ws/lib/websocket-server.js', | ||
'google-gax/build/src/grpc.js', | ||
'cookie-signature/index.js' | ||
) | ||
const EXCLUDED_PATHS_FROM_STACK = [ | ||
path.join('node_modules', 'object-hash', path.sep) | ||
path.join('node_modules', 'object-hash', path.sep), | ||
path.join('node_modules', 'aws-sdk', 'lib', 'util.js'), | ||
path.join('node_modules', 'keygrip', path.sep) | ||
] | ||
@@ -30,0 +34,0 @@ class WeakHashAnalyzer extends Analyzer { |
@@ -7,3 +7,3 @@ 'use strict' | ||
function taintObject (iastContext, object, type, keyTainting, keyType) { | ||
function taintObject (iastContext, object, type) { | ||
let result = object | ||
@@ -26,5 +26,2 @@ const transactionId = iastContext?.[IAST_TRANSACTION_ID] | ||
result = tainted | ||
} else if (keyTainting && key) { | ||
const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType) | ||
parent[taintedProperty] = tainted | ||
} else { | ||
@@ -39,7 +36,2 @@ parent[key] = tainted | ||
} | ||
if (parent && keyTainting && key) { | ||
const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType) | ||
parent[taintedProperty] = value | ||
} | ||
} | ||
@@ -46,0 +38,0 @@ } catch (e) { |
@@ -98,8 +98,10 @@ 'use strict' | ||
const iastContext = getIastContext(storage.getStore()) | ||
taintObject(iastContext, target, HTTP_REQUEST_COOKIE_VALUE, true, HTTP_REQUEST_COOKIE_NAME) | ||
// Prevent tainting cookie names since it leads to taint literal string with same value. | ||
taintObject(iastContext, target, HTTP_REQUEST_COOKIE_VALUE) | ||
} | ||
taintHeaders (headers, iastContext) { | ||
// Prevent tainting header names since it leads to taint literal string with same value. | ||
this.execSource({ | ||
handler: () => taintObject(iastContext, headers, HTTP_REQUEST_HEADER_VALUE, true, HTTP_REQUEST_HEADER_NAME), | ||
handler: () => taintObject(iastContext, headers, HTTP_REQUEST_HEADER_VALUE), | ||
tags: REQ_HEADER_TAGS, | ||
@@ -106,0 +108,0 @@ iastContext |
module.exports = { | ||
COMMAND_INJECTION: 'COMMAND_INJECTION', | ||
HARDCODED_PASSWORD: 'HARDCODED_PASSWORD', | ||
HARDCODED_SECRET: 'HARDCODED_SECRET', | ||
@@ -4,0 +5,0 @@ HEADER_INJECTION: 'HEADER_INJECTION', |
@@ -11,3 +11,3 @@ 'use strict' | ||
function enable (config) { | ||
function enable (config, appsec) { | ||
rc = new RemoteConfigManager(config) | ||
@@ -35,3 +35,3 @@ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_CUSTOM_TAGS, true) | ||
if (activation === Activation.ONECLICK) { | ||
enableOrDisableAppsec(action, rcConfig, config) | ||
enableOrDisableAppsec(action, rcConfig, config, appsec) | ||
} | ||
@@ -46,3 +46,3 @@ | ||
function enableOrDisableAppsec (action, rcConfig, config) { | ||
function enableOrDisableAppsec (action, rcConfig, config, appsec) { | ||
if (typeof rcConfig.asm?.enabled === 'boolean') { | ||
@@ -58,5 +58,5 @@ let shouldEnable | ||
if (shouldEnable) { | ||
require('..').enable(config) | ||
appsec.enable(config) | ||
} else { | ||
require('..').disable() | ||
appsec.disable() | ||
} | ||
@@ -63,0 +63,0 @@ } |
@@ -11,3 +11,4 @@ 'use strict' | ||
incrementWafUpdatesMetric, | ||
incrementWafRequestsMetric | ||
incrementWafRequestsMetric, | ||
getRequestMetrics | ||
} = require('./telemetry') | ||
@@ -96,3 +97,2 @@ const zlib = require('zlib') | ||
function reportMetrics (metrics) { | ||
// TODO: metrics should be incremental, there already is an RFC to report metrics | ||
const store = storage.getStore() | ||
@@ -102,10 +102,2 @@ const rootSpan = store?.req && web.root(store.req) | ||
if (metrics.duration) { | ||
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration) | ||
} | ||
if (metrics.durationExt) { | ||
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt) | ||
} | ||
if (metrics.rulesVersion) { | ||
@@ -185,2 +177,11 @@ rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion) | ||
const metrics = getRequestMetrics(req) | ||
if (metrics?.duration) { | ||
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration) | ||
} | ||
if (metrics?.durationExt) { | ||
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt) | ||
} | ||
incrementWafRequestsMetric(req) | ||
@@ -187,0 +188,0 @@ |
@@ -8,2 +8,3 @@ 'use strict' | ||
const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') | ||
const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') | ||
@@ -30,6 +31,15 @@ const tags = { | ||
function newStore () { | ||
return { | ||
[DD_TELEMETRY_REQUEST_METRICS]: { | ||
duration: 0, | ||
durationExt: 0 | ||
} | ||
} | ||
} | ||
function getStore (req) { | ||
let store = metricsStoreMap.get(req) | ||
if (!store) { | ||
store = {} | ||
store = newStore() | ||
metricsStoreMap.set(req, store) | ||
@@ -56,5 +66,3 @@ } | ||
function getOrCreateMetricTags (req, versionsTags) { | ||
const store = getStore(req) | ||
function getOrCreateMetricTags (store, versionsTags) { | ||
let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] | ||
@@ -75,4 +83,11 @@ if (!metricTags) { | ||
function updateWafRequestsMetricTags (metrics, req) { | ||
if (!req || !enabled) return | ||
if (!req) return | ||
const store = getStore(req) | ||
// it does not depend on whether telemetry is enabled or not | ||
addRequestMetrics(store, metrics) | ||
if (!enabled) return | ||
const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) | ||
@@ -82,3 +97,3 @@ | ||
const metricTags = getOrCreateMetricTags(req, versionsTags) | ||
const metricTags = getOrCreateMetricTags(store, versionsTags) | ||
@@ -129,2 +144,14 @@ const { blockTriggered, ruleTriggered, wafTimeout } = metrics | ||
function addRequestMetrics (store, { duration, durationExt }) { | ||
store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0 | ||
store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0 | ||
} | ||
function getRequestMetrics (req) { | ||
if (req) { | ||
const store = getStore(req) | ||
return store?.[DD_TELEMETRY_REQUEST_METRICS] | ||
} | ||
} | ||
module.exports = { | ||
@@ -137,3 +164,5 @@ enable, | ||
incrementWafUpdatesMetric, | ||
incrementWafRequestsMetric | ||
incrementWafRequestsMetric, | ||
getRequestMetrics | ||
} |
@@ -192,3 +192,4 @@ 'use strict' | ||
isEarlyFlakeDetectionEnabled, | ||
earlyFlakeDetectionNumRetries | ||
earlyFlakeDetectionNumRetries, | ||
earlyFlakeDetectionFaultyThreshold | ||
} = remoteConfiguration | ||
@@ -201,3 +202,4 @@ return { | ||
isEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled && this._config.isEarlyFlakeDetectionEnabled, | ||
earlyFlakeDetectionNumRetries | ||
earlyFlakeDetectionNumRetries, | ||
earlyFlakeDetectionFaultyThreshold | ||
} | ||
@@ -204,0 +206,0 @@ } |
@@ -117,2 +117,6 @@ const fs = require('fs') | ||
if (commitsToUpload === null) { | ||
return callback(new Error('git rev-list failed')) | ||
} | ||
callback(null, commitsToUpload) | ||
@@ -256,5 +260,4 @@ }) | ||
const latestCommits = getLatestCommits() | ||
let latestCommits = getLatestCommits() | ||
log.debug(`There were ${latestCommits.length} commits since last month.`) | ||
const [headCommit] = latestCommits | ||
@@ -273,2 +276,3 @@ const getOnFinishGetCommitsToUpload = (hasCheckedShallow) => (err, commitsToUpload) => { | ||
if (hasCheckedShallow || !isShallowRepository()) { | ||
const [headCommit] = latestCommits | ||
return generateAndUploadPackFiles({ | ||
@@ -286,2 +290,5 @@ url, | ||
unshallowRepository() | ||
// The latest commits change after unshallowing | ||
latestCommits = getLatestCommits() | ||
getCommitsToUpload({ | ||
@@ -288,0 +295,0 @@ url, |
@@ -15,2 +15,3 @@ const request = require('../../exporters/common/request') | ||
const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2 | ||
const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30 | ||
@@ -108,3 +109,5 @@ function getLibraryConfiguration ({ | ||
earlyFlakeDetectionNumRetries: | ||
earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES | ||
earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES, | ||
earlyFlakeDetectionFaultyThreshold: | ||
earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD | ||
} | ||
@@ -111,0 +114,0 @@ |
@@ -18,5 +18,61 @@ 'use strict' | ||
const { updateConfig } = require('./telemetry') | ||
const telemetryMetrics = require('./telemetry/metrics') | ||
const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless') | ||
const { ORIGIN_KEY } = require('./constants') | ||
const tracerMetrics = telemetryMetrics.manager.namespace('tracers') | ||
const telemetryCounters = { | ||
'otel.env.hiding': {}, | ||
'otel.env.invalid': {} | ||
} | ||
function getCounter (event, ddVar, otelVar, otelTracesSamplerArg) { | ||
const counters = telemetryCounters[event] | ||
const tags = [] | ||
if (ddVar) tags.push(ddVar) | ||
if (otelVar) tags.push(otelVar) | ||
if (otelTracesSamplerArg) tags.push(otelTracesSamplerArg) | ||
if (!(ddVar in counters)) counters[ddVar] = {} | ||
const counter = tracerMetrics.count(event, tags) | ||
counters[ddVar][otelVar] = counter | ||
return counter | ||
} | ||
const otelDdEnvMapping = { | ||
DD_TRACE_LOG_LEVEL: 'OTEL_LOG_LEVEL', | ||
DD_TRACE_PROPAGATION_STYLE: 'OTEL_PROPAGATORS', | ||
DD_SERVICE: 'OTEL_SERVICE_NAME', | ||
DD_TRACE_SAMPLE_RATE: 'OTEL_TRACES_SAMPLER', | ||
DD_TRACE_ENABLED: 'OTEL_TRACES_EXPORTER', | ||
DD_RUNTIME_METRICS_ENABLED: 'OTEL_METRICS_EXPORTER', | ||
DD_TAGS: 'OTEL_RESOURCE_ATTRIBUTES', | ||
DD_TRACE_OTEL_ENABLED: 'OTEL_SDK_DISABLED' | ||
} | ||
const otelInvalidEnv = ['OTEL_LOGS_EXPORTER'] | ||
function checkIfBothOtelAndDdEnvVarSet () { | ||
for (const [ddVar, otelVar] of Object.entries(otelDdEnvMapping)) { | ||
if (process.env[ddVar] && process.env[otelVar]) { | ||
log.warn(`both ${ddVar} and ${otelVar} environment variables are set`) | ||
getCounter('otel.env.hiding', ddVar, otelVar, | ||
otelVar === 'OTEL_TRACES_SAMPLER' && | ||
process.env.OTEL_TRACES_SAMPLER_ARG | ||
? 'OTEL_TRACES_SAMPLER_ARG' | ||
: undefined).inc() | ||
} | ||
} | ||
for (const otelVar of otelInvalidEnv) { | ||
if (process.env[otelVar]) { | ||
log.warn(`${otelVar} is not supported by the Datadog SDK`) | ||
getCounter('otel.env.invalid', otelVar).inc() | ||
} | ||
} | ||
} | ||
const fromEntries = Object.fromEntries || (entries => | ||
@@ -31,2 +87,3 @@ entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {})) | ||
const defaultWafObfuscatorValueRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}' | ||
const runtimeId = uuid() | ||
@@ -93,3 +150,4 @@ function maybeFile (filepath) { | ||
const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}` | ||
const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE) | ||
const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE, process.env.OTEL_PROPAGATORS) | ||
if (typeof envVar !== 'undefined') { | ||
@@ -113,2 +171,4 @@ return envVar.split(',') | ||
checkIfBothOtelAndDdEnvVarSet() | ||
// Configure the logger first so it can be used to warn about other configs | ||
@@ -120,5 +180,7 @@ this.debug = isTrue(coalesce( | ||
this.logger = options.logger | ||
this.logLevel = coalesce( | ||
options.logLevel, | ||
process.env.DD_TRACE_LOG_LEVEL, | ||
process.env.OTEL_LOG_LEVEL, | ||
'debug' | ||
@@ -170,3 +232,3 @@ ) | ||
} | ||
const DD_TRACE_PROPAGATION_STYLE_INJECT = propagationStyle( | ||
const PROPAGATION_STYLE_INJECT = propagationStyle( | ||
'inject', | ||
@@ -176,3 +238,3 @@ options.tracePropagationStyle, | ||
) | ||
const DD_TRACE_PROPAGATION_STYLE_EXTRACT = propagationStyle( | ||
const PROPAGATION_STYLE_EXTRACT = propagationStyle( | ||
'extract', | ||
@@ -262,4 +324,9 @@ options.tracePropagationStyle, | ||
this.tracePropagationStyle = { | ||
inject: DD_TRACE_PROPAGATION_STYLE_INJECT, | ||
extract: DD_TRACE_PROPAGATION_STYLE_EXTRACT | ||
inject: PROPAGATION_STYLE_INJECT, | ||
extract: PROPAGATION_STYLE_EXTRACT, | ||
otelPropagators: process.env.DD_TRACE_PROPAGATION_STYLE || | ||
process.env.DD_TRACE_PROPAGATION_STYLE_INJECT || | ||
process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT | ||
? false | ||
: !!process.env.OTEL_PROPAGATORS | ||
} | ||
@@ -302,3 +369,3 @@ this.tracePropagationExtractFirst = isTrue(DD_TRACE_PROPAGATION_EXTRACT_FIRST) | ||
version: this.version, | ||
'runtime-id': uuid() | ||
'runtime-id': runtimeId | ||
}) | ||
@@ -537,3 +604,8 @@ | ||
DD_TRACING_ENABLED, | ||
DD_VERSION | ||
DD_VERSION, | ||
OTEL_SERVICE_NAME, | ||
OTEL_RESOURCE_ATTRIBUTES, | ||
OTEL_TRACES_SAMPLER, | ||
OTEL_TRACES_SAMPLER_ARG, | ||
OTEL_METRICS_EXPORTER | ||
} = process.env | ||
@@ -544,2 +616,3 @@ | ||
tagger.add(tags, OTEL_RESOURCE_ATTRIBUTES, true) | ||
tagger.add(tags, DD_TAGS) | ||
@@ -605,7 +678,20 @@ tagger.add(tags, DD_TRACE_TAGS) | ||
this._setBoolean(env, 'reportHostname', DD_TRACE_REPORT_HOSTNAME) | ||
this._setBoolean(env, 'runtimeMetrics', DD_RUNTIME_METRICS_ENABLED) | ||
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE) | ||
// only used to explicitly set runtimeMetrics to false | ||
const otelSetRuntimeMetrics = String(OTEL_METRICS_EXPORTER).toLowerCase() === 'none' | ||
? false | ||
: undefined | ||
this._setBoolean(env, 'runtimeMetrics', DD_RUNTIME_METRICS_ENABLED || | ||
otelSetRuntimeMetrics) | ||
const OTEL_TRACES_SAMPLER_MAPPING = { | ||
always_on: '1.0', | ||
always_off: '0.0', | ||
traceidratio: OTEL_TRACES_SAMPLER_ARG, | ||
parentbased_always_on: '1.0', | ||
parentbased_always_off: '0.0', | ||
parentbased_traceidratio: OTEL_TRACES_SAMPLER_ARG | ||
} | ||
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE || OTEL_TRACES_SAMPLER_MAPPING[OTEL_TRACES_SAMPLER]) | ||
this._setValue(env, 'sampler.rateLimit', DD_TRACE_RATE_LIMIT) | ||
this._setString(env, 'scope', DD_TRACE_SCOPE) | ||
this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service) | ||
this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service || OTEL_SERVICE_NAME) | ||
this._setString(env, 'site', DD_SITE) | ||
@@ -838,2 +924,3 @@ if (DD_TRACE_SPAN_ATTRIBUTE_SCHEMA) { | ||
tagger.add(tags, options.tracing_tags) | ||
if (Object.keys(tags).length) tags['runtime-id'] = runtimeId | ||
@@ -840,0 +927,0 @@ this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate) |
@@ -15,2 +15,3 @@ 'use strict' | ||
const TYPE_DISTRIBUTION = 'd' | ||
const TYPE_HISTOGRAM = 'h' | ||
@@ -50,2 +51,6 @@ class DogStatsDClient { | ||
histogram (stat, value, tags) { | ||
this._add(stat, value, TYPE_HISTOGRAM, tags) | ||
} | ||
flush () { | ||
@@ -185,12 +190,2 @@ const queue = this._enqueue() | ||
class NoopDogStatsDClient { | ||
gauge () { } | ||
increment () { } | ||
distribution () { } | ||
flush () { } | ||
} | ||
// This is a simplified user-facing proxy to the underlying DogStatsDClient instance | ||
@@ -235,2 +230,10 @@ class CustomMetrics { | ||
histogram (stat, value, tags) { | ||
return this.dogstatsd.histogram( | ||
stat, | ||
value, | ||
CustomMetrics.tagTranslator(tags) | ||
) | ||
} | ||
flush () { | ||
@@ -259,4 +262,3 @@ return this.dogstatsd.flush() | ||
DogStatsDClient, | ||
NoopDogStatsDClient, | ||
CustomMetrics | ||
} |
@@ -8,4 +8,8 @@ 'use strict' | ||
module.exports = isFalse(process.env.DD_TRACE_ENABLED) || inJestWorker | ||
const ddTraceDisabled = process.env.DD_TRACE_ENABLED | ||
? isFalse(process.env.DD_TRACE_ENABLED) | ||
: String(process.env.OTEL_TRACES_EXPORTER).toLowerCase() === 'none' | ||
module.exports = ddTraceDisabled || inJestWorker | ||
? require('./noop/proxy') | ||
: require('./proxy') |
@@ -5,5 +5,7 @@ 'use strict' | ||
const NoopAppsecSdk = require('../appsec/sdk/noop') | ||
const NoopDogStatsDClient = require('./dogstatsd') | ||
const noop = new NoopTracer() | ||
const noopAppsec = new NoopAppsecSdk() | ||
const noopDogStatsDClient = new NoopDogStatsDClient() | ||
@@ -14,2 +16,3 @@ class Tracer { | ||
this.appsec = noopAppsec | ||
this.dogstatsd = noopDogStatsDClient | ||
} | ||
@@ -16,0 +19,0 @@ |
@@ -227,9 +227,15 @@ 'use strict' | ||
break | ||
case 'b3': // TODO: should match "b3 single header" in next major | ||
case 'b3' && this | ||
._config | ||
.tracePropagationStyle | ||
.otelPropagators: // TODO: should match "b3 single header" in next major | ||
case 'b3 single header': // TODO: delete in major after singular "b3" | ||
spanContext = this._extractB3SingleContext(carrier) | ||
break | ||
case 'b3': | ||
case 'b3multi': | ||
spanContext = this._extractB3MultiContext(carrier) | ||
break | ||
case 'b3 single header': // TODO: delete in major after singular "b3" | ||
spanContext = this._extractB3SingleContext(carrier) | ||
break | ||
default: | ||
log.warn(`Unknown propagation style: ${extractor}`) | ||
} | ||
@@ -236,0 +242,0 @@ |
@@ -36,2 +36,3 @@ 'use strict' | ||
const startCh = channel('dd-trace:span:start') | ||
const finishCh = channel('dd-trace:span:finish') | ||
@@ -100,2 +101,3 @@ | ||
spanleak.addSpan(this, operationName) | ||
startCh.publish(this) | ||
} | ||
@@ -102,0 +104,0 @@ |
@@ -48,2 +48,3 @@ 'use strict' | ||
get 'jest-jasmine2' () { return require('../../../datadog-plugin-jest/src') }, | ||
get 'jest-runtime' () { return require('../../../datadog-plugin-jest/src') }, | ||
get 'jest-worker' () { return require('../../../datadog-plugin-jest/src') }, | ||
@@ -81,2 +82,3 @@ get koa () { return require('../../../datadog-plugin-koa/src') }, | ||
get router () { return require('../../../datadog-plugin-router/src') }, | ||
get 'selenium-webdriver' () { return require('../../../datadog-plugin-selenium/src') }, | ||
get sharedb () { return require('../../../datadog-plugin-sharedb/src') }, | ||
@@ -83,0 +85,0 @@ get tedious () { return require('../../../datadog-plugin-tedious/src') }, |
@@ -31,3 +31,3 @@ const cp = require('child_process') | ||
const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB | ||
const GIT_REV_LIST_MAX_BUFFER = 12 * 1024 * 1024 // 12MB | ||
@@ -57,7 +57,11 @@ function sanitizedExec ( | ||
return result | ||
} catch (e) { | ||
} catch (err) { | ||
if (errorMetric) { | ||
incrementCountMetric(errorMetric.name, { ...errorMetric.tags, exitCode: e.status }) | ||
incrementCountMetric(errorMetric.name, { | ||
...errorMetric.tags, | ||
errorType: err.code, | ||
exitCode: err.status || err.errno | ||
}) | ||
} | ||
log.error(e) | ||
log.error(err) | ||
return '' | ||
@@ -134,3 +138,6 @@ } finally { | ||
log.error(err) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'unshallow', exitCode: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'unshallow', errorType: err.code, exitCode: err.status || err.errno } | ||
) | ||
const upstreamRemote = sanitizedExec('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}']) | ||
@@ -145,3 +152,6 @@ try { | ||
log.error(err) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'unshallow', exitCode: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'unshallow', errorType: err.code, exitCode: err.status || err.errno } | ||
) | ||
// We use sanitizedExec here because if this last option fails, we'll give up. | ||
@@ -182,3 +192,6 @@ sanitizedExec( | ||
log.error(`Get latest commits failed: ${err.message}`) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'get_local_commits', errorType: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'get_local_commits', errorType: err.status } | ||
) | ||
return [] | ||
@@ -189,3 +202,3 @@ } | ||
function getCommitsRevList (commitsToExclude, commitsToInclude) { | ||
let result = [] | ||
let result = null | ||
@@ -214,3 +227,6 @@ const commitsToExcludeString = commitsToExclude.map(commit => `^${commit}`) | ||
log.error(`Get commits to upload failed: ${err.message}`) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'get_objects', errorType: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'get_objects', errorType: err.code, exitCode: err.status || err.errno } // err.status might be null | ||
) | ||
} | ||
@@ -255,3 +271,6 @@ distributionMetric(TELEMETRY_GIT_COMMAND_MS, { command: 'get_objects' }, Date.now() - startTime) | ||
log.error(err) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'pack_objects', errorType: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'pack_objects', exitCode: err.status || err.errno, errorType: err.code } | ||
) | ||
/** | ||
@@ -273,3 +292,6 @@ * The generation of pack files in the temporary folder (from `os.tmpdir()`) | ||
log.error(err) | ||
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'pack_objects', errorType: err.status }) | ||
incrementCountMetric( | ||
TELEMETRY_GIT_COMMAND_ERRORS, | ||
{ command: 'pack_objects', exitCode: err.status || err.errno, errorType: err.code } | ||
) | ||
} | ||
@@ -276,0 +298,0 @@ } |
@@ -56,3 +56,4 @@ const path = require('path') | ||
const TEST_IS_RETRY = 'test.is_retry' | ||
const TEST_EARLY_FLAKE_IS_ENABLED = 'test.early_flake.is_enabled' | ||
const TEST_EARLY_FLAKE_ENABLED = 'test.early_flake.enabled' | ||
const TEST_EARLY_FLAKE_ABORT_REASON = 'test.early_flake.abort_reason' | ||
@@ -75,2 +76,8 @@ const CI_APP_ORIGIN = 'ciapp-test' | ||
// selenium tags | ||
const TEST_BROWSER_DRIVER = 'test.browser.driver' | ||
const TEST_BROWSER_DRIVER_VERSION = 'test.browser.driver_version' | ||
const TEST_BROWSER_NAME = 'test.browser.name' | ||
const TEST_BROWSER_VERSION = 'test.browser.version' | ||
// jest worker variables | ||
@@ -107,3 +114,4 @@ const JEST_WORKER_TRACE_PAYLOAD_CODE = 60 | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED, | ||
TEST_EARLY_FLAKE_ENABLED, | ||
TEST_EARLY_FLAKE_ABORT_REASON, | ||
getTestEnvironmentMetadata, | ||
@@ -147,3 +155,8 @@ getTestParametersString, | ||
removeEfdStringFromTestName, | ||
addEfdStringToTestName | ||
addEfdStringToTestName, | ||
getIsFaultyEarlyFlakeDetection, | ||
TEST_BROWSER_DRIVER, | ||
TEST_BROWSER_DRIVER_VERSION, | ||
TEST_BROWSER_NAME, | ||
TEST_BROWSER_VERSION | ||
} | ||
@@ -578,1 +591,19 @@ | ||
} | ||
function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faultyThresholdPercentage) { | ||
let newSuites = 0 | ||
for (const suite of projectSuites) { | ||
if (!testsBySuiteName[suite]) { | ||
newSuites++ | ||
} | ||
} | ||
const newSuitesPercentage = (newSuites / projectSuites.length) * 100 | ||
// The faulty threshold represents a percentage, but we also want to consider | ||
// smaller projects, where big variations in the % are more likely. | ||
// This is why we also check the absolute number of new suites. | ||
return ( | ||
newSuites > faultyThresholdPercentage && | ||
newSuitesPercentage > faultyThresholdPercentage | ||
) | ||
} |
@@ -24,2 +24,3 @@ 'use strict' | ||
DD_PROFILING_CODEHOTSPOTS_ENABLED, | ||
DD_PROFILING_CPU_ENABLED, | ||
DD_PROFILING_DEBUG_SOURCE_MAPS, | ||
@@ -169,3 +170,3 @@ DD_PROFILING_ENABLED, | ||
DD_PROFILING_TIMELINE_ENABLED, | ||
DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, false)) | ||
DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, samplingContextsAvailable)) | ||
logExperimentalVarDeprecation('TIMELINE_ENABLED') | ||
@@ -181,3 +182,5 @@ checkOptionWithSamplingContextAllowed(this.timelineEnabled, 'Timeline view') | ||
this.cpuProfilingEnabled = isTrue(coalesce(options.cpuProfilingEnabled, | ||
DD_PROFILING_EXPERIMENTAL_CPU_ENABLED, false)) | ||
DD_PROFILING_CPU_ENABLED, | ||
DD_PROFILING_EXPERIMENTAL_CPU_ENABLED, samplingContextsAvailable)) | ||
logExperimentalVarDeprecation('CPU_ENABLED') | ||
checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling') | ||
@@ -294,4 +297,5 @@ | ||
// Events profiler is a profiler for timeline events | ||
if (options.timelineEnabled) { | ||
// Events profiler is a profiler that produces timeline events. It is only | ||
// added if timeline is enabled and there's a wall profiler. | ||
if (options.timelineEnabled && profilers.some(p => p instanceof WallProfiler)) { | ||
profilers.push(new EventsProfiler(options)) | ||
@@ -298,0 +302,0 @@ } |
@@ -13,2 +13,3 @@ 'use strict' | ||
const os = require('os') | ||
const { urlToHttpOptions } = require('url') | ||
const perf = require('perf_hooks').performance | ||
@@ -181,5 +182,6 @@ | ||
} else { | ||
options.protocol = this._url.protocol | ||
options.hostname = this._url.hostname | ||
options.port = this._url.port | ||
const httpOptions = urlToHttpOptions(this._url) | ||
options.protocol = httpOptions.protocol | ||
options.hostname = httpOptions.hostname | ||
options.port = httpOptions.port | ||
} | ||
@@ -186,0 +188,0 @@ |
@@ -7,3 +7,6 @@ 'use strict' | ||
const { threadNamePrefix } = require('./profilers/shared') | ||
const dc = require('dc-polyfill') | ||
const profileSubmittedChannel = dc.channel('datadog:profiling:profile-submitted') | ||
function maybeSourceMap (sourceMap, SourceMapper, debug) { | ||
@@ -165,2 +168,3 @@ if (!sourceMap) return | ||
await this._submit(encodedProfiles, startDate, endDate, snapshotKind) | ||
profileSubmittedChannel.publish() | ||
this._logger.debug('Submitted profiles') | ||
@@ -167,0 +171,0 @@ } catch (err) { |
@@ -14,4 +14,21 @@ 'use strict' | ||
const dogstatsd = require('./dogstatsd') | ||
const NoopDogStatsDClient = require('./noop/dogstatsd') | ||
const spanleak = require('./spanleak') | ||
const { SSITelemetry } = require('./profiling/ssi-telemetry') | ||
class LazyModule { | ||
constructor (provider) { | ||
this.provider = provider | ||
} | ||
enable (...args) { | ||
this.module = this.provider() | ||
this.module.enable(...args) | ||
} | ||
disable () { | ||
this.module?.disable() | ||
} | ||
} | ||
class Tracer extends NoopProxy { | ||
@@ -24,4 +41,10 @@ constructor () { | ||
this._pluginManager = new PluginManager(this) | ||
this.dogstatsd = new dogstatsd.NoopDogStatsDClient() | ||
this.dogstatsd = new NoopDogStatsDClient() | ||
this._tracingInitialized = false | ||
// these requires must work with esm bundler | ||
this._modules = { | ||
appsec: new LazyModule(() => require('./appsec')), | ||
iast: new LazyModule(() => require('./appsec/iast')) | ||
} | ||
} | ||
@@ -61,3 +84,3 @@ | ||
if (config.remoteConfig.enabled && !config.isCiVisibility) { | ||
const rc = remoteConfig.enable(config) | ||
const rc = remoteConfig.enable(config, this._modules.appsec) | ||
@@ -78,2 +101,4 @@ rc.on('APM_TRACING', (action, conf) => { | ||
const ssiTelemetry = new SSITelemetry() | ||
ssiTelemetry.start() | ||
if (config.profiling.enabled) { | ||
@@ -87,2 +112,4 @@ // do not stop tracer initialization if the profiler fails to be imported | ||
} | ||
} else if (ssiTelemetry.enabled()) { | ||
require('./profiling/ssi-telemetry-mock-profiler').start(config) | ||
} | ||
@@ -115,5 +142,4 @@ if (!this._profilerStarted) { | ||
if (config.tracing !== false) { | ||
// dirty require for now so zero appsec code is executed unless explicitly enabled | ||
if (config.appsec.enabled) { | ||
require('./appsec').enable(config) | ||
this._modules.appsec.enable(config) | ||
} | ||
@@ -126,7 +152,7 @@ if (!this._tracingInitialized) { | ||
if (config.iast.enabled) { | ||
require('./appsec/iast').enable(config, this._tracer) | ||
this._modules.iast.enable(config, this._tracer) | ||
} | ||
} else if (this._tracingInitialized) { | ||
require('./appsec').disable() | ||
require('./appsec/iast').disable() | ||
this._modules.appsec.disable() | ||
this._modules.iast.disable() | ||
} | ||
@@ -133,0 +159,0 @@ |
@@ -5,3 +5,9 @@ 'use strict' | ||
function add (carrier, keyValuePairs) { | ||
const otelTagMap = { | ||
'deployment.environment': 'env', | ||
'service.name': 'service', | ||
'service.version': 'version' | ||
} | ||
function add (carrier, keyValuePairs, parseOtelTags = false) { | ||
if (!carrier || !keyValuePairs) return | ||
@@ -17,8 +23,12 @@ | ||
for (const segment of segments) { | ||
const separatorIndex = segment.indexOf(':') | ||
const separatorIndex = parseOtelTags ? segment.indexOf('=') : segment.indexOf(':') | ||
if (separatorIndex === -1) continue | ||
const key = segment.slice(0, separatorIndex) | ||
let key = segment.slice(0, separatorIndex) | ||
const value = segment.slice(separatorIndex + 1) | ||
if (parseOtelTags && key in otelTagMap) { | ||
key = otelTagMap[key] | ||
} | ||
carrier[key.trim()] = value.trim() | ||
@@ -25,0 +35,0 @@ } |
@@ -13,2 +13,3 @@ 'use strict' | ||
const telemetryStopChannel = dc.channel('datadog:telemetry:stop') | ||
const telemetryAppClosingChannel = dc.channel('datadog:telemetry:app-closing') | ||
@@ -133,8 +134,8 @@ let config | ||
} | ||
// Give chance to listeners to update metrics before shutting down. | ||
telemetryAppClosingChannel.publish() | ||
const { reqType, payload } = createPayload('app-closing') | ||
sendData(config, application, host, reqType, payload) | ||
// we flush before shutting down. Only in CI Visibility | ||
if (config.isCiVisibility) { | ||
metricsManager.send(config, application, host) | ||
} | ||
// We flush before shutting down. | ||
metricsManager.send(config, application, host) | ||
} | ||
@@ -141,0 +142,0 @@ |
@@ -78,4 +78,4 @@ 'use strict' | ||
dec (value = -1) { | ||
return this.track(value) | ||
dec (value = 1) { | ||
return this.track(-value) | ||
} | ||
@@ -82,0 +82,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 7 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1761492
530
51035
168
24
+ Added@datadog/native-appsec@7.1.1(transitive)
+ Added@datadog/pprof@5.2.0(transitive)
- Removed@datadog/native-appsec@7.1.0(transitive)
- Removed@datadog/pprof@5.1.0(transitive)
Updated@datadog/native-appsec@7.1.1
Updated@datadog/pprof@5.2.0
Updatedpprof-format@^2.1.0