dd-trace
Advanced tools
Comparing version 6.0.0-pre-c3e3d62 to 6.0.0-pre-c879030
{ | ||
"name": "dd-trace", | ||
"version": "6.0.0-pre-c3e3d62", | ||
"version": "6.0.0-pre-c879030", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -72,7 +72,7 @@ "main": "index.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", | ||
@@ -99,3 +99,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", | ||
@@ -102,0 +102,0 @@ "retry": "^0.13.1", |
@@ -295,2 +295,4 @@ 'use strict' | ||
knownTests = knownTestsResponse.knownTests | ||
} else { | ||
isEarlyFlakeDetectionEnabled = false | ||
} | ||
@@ -297,0 +299,0 @@ } |
'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)) | ||
} |
@@ -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 | ||
} | ||
@@ -418,2 +472,5 @@ } catch (err) { | ||
knownTests = receivedKnownTests | ||
} else { | ||
// We disable EFD if there has been an error in the known tests request | ||
isEarlyFlakeDetectionEnabled = false | ||
} | ||
@@ -512,2 +569,3 @@ } catch (err) { | ||
isEarlyFlakeDetectionEnabled, | ||
isEarlyFlakeDetectionFaulty, | ||
onDone | ||
@@ -524,2 +582,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 | ||
@@ -636,3 +716,2 @@ }) | ||
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled | ||
config.testEnvironmentOptions._ddKnownTests = knownTests | ||
}) | ||
@@ -730,9 +809,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. | ||
@@ -745,6 +837,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 | ||
@@ -815,2 +905,34 @@ | ||
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 () { | ||
@@ -817,0 +939,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 @@ } |
@@ -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) { |
@@ -39,3 +39,3 @@ const semver = require('semver') | ||
let earlyFlakeDetectionNumRetries = 0 | ||
let knownTests = [] | ||
let knownTests = {} | ||
let rootDir = '' | ||
@@ -411,2 +411,4 @@ const MINIMUM_SUPPORTED_VERSION_EFD = '1.38.0' | ||
knownTests = receivedKnownTests | ||
} else { | ||
isEarlyFlakeDetectionEnabled = false | ||
} | ||
@@ -439,3 +441,7 @@ } catch (err) { | ||
testSessionAsyncResource.runInAsyncScope(() => { | ||
testSessionFinishCh.publish({ status: STATUS_TO_TEST_STATUS[sessionStatus], onDone }) | ||
testSessionFinishCh.publish({ | ||
status: STATUS_TO_TEST_STATUS[sessionStatus], | ||
isEarlyFlakeDetectionEnabled, | ||
onDone | ||
}) | ||
}) | ||
@@ -442,0 +448,0 @@ await flushWait |
@@ -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') | ||
@@ -331,2 +331,3 @@ const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util') | ||
log.error(knownTestsResponse.err) | ||
this.isEarlyFlakeDetectionEnabled = false | ||
} else { | ||
@@ -368,3 +369,3 @@ // We use TEST_FRAMEWORK_NAME for the name of the module | ||
if (this.isEarlyFlakeDetectionEnabled) { | ||
testSessionSpanMetadata[TEST_EARLY_FLAKE_IS_ENABLED] = 'true' | ||
testSessionSpanMetadata[TEST_EARLY_FLAKE_ENABLED] = 'true' | ||
} | ||
@@ -371,0 +372,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,23 @@ 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 }) | ||
ctx.headers = headers | ||
ctx.req = new globalThis.Request(req, { headers }) | ||
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') | ||
@@ -227,3 +227,3 @@ const { COMPONENT } = require('../../dd-trace/src/constants') | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_IS_ENABLED, 'true') | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
@@ -230,0 +230,0 @@ |
'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 @@ |
@@ -16,3 +16,4 @@ 'use strict' | ||
TEST_IS_NEW, | ||
TEST_IS_RETRY | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_ENABLED | ||
} = require('../../dd-trace/src/plugins/util/test') | ||
@@ -39,6 +40,10 @@ const { RESOURCE_NAME } = require('../../../ext/tags') | ||
this.addSub('ci:playwright:session:finish', ({ status, onDone }) => { | ||
this.addSub('ci:playwright:session:finish', ({ status, isEarlyFlakeDetectionEnabled, onDone }) => { | ||
this.testModuleSpan.setTag(TEST_STATUS, status) | ||
this.testSessionSpan.setTag(TEST_STATUS, status) | ||
if (isEarlyFlakeDetectionEnabled) { | ||
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true') | ||
} | ||
if (this.numFailedSuites > 0) { | ||
@@ -45,0 +50,0 @@ let errorMessage = `Test suites failed: ${this.numFailedSuites}.` |
@@ -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 { |
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,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 @@ |
@@ -30,2 +30,3 @@ 'use strict' | ||
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() | ||
@@ -295,3 +296,3 @@ function maybeFile (filepath) { | ||
version: this.version, | ||
'runtime-id': uuid() | ||
'runtime-id': runtimeId | ||
}) | ||
@@ -828,2 +829,3 @@ | ||
tagger.add(tags, options.tracing_tags) | ||
if (Object.keys(tags).length) tags['runtime-id'] = runtimeId | ||
@@ -830,0 +832,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 | ||
} |
@@ -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 @@ |
@@ -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 @@ |
@@ -126,2 +126,3 @@ const { | ||
log.error(`Known tests could not be fetched. ${err.message}`) | ||
this.libraryConfig.isEarlyFlakeDetectionEnabled = false | ||
} | ||
@@ -128,0 +129,0 @@ onDone({ err, knownTests }) |
@@ -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' | ||
@@ -106,3 +107,4 @@ const CI_APP_ORIGIN = 'ciapp-test' | ||
TEST_IS_RETRY, | ||
TEST_EARLY_FLAKE_IS_ENABLED, | ||
TEST_EARLY_FLAKE_ENABLED, | ||
TEST_EARLY_FLAKE_ABORT_REASON, | ||
getTestEnvironmentMetadata, | ||
@@ -146,3 +148,4 @@ getTestParametersString, | ||
removeEfdStringFromTestName, | ||
addEfdStringToTestName | ||
addEfdStringToTestName, | ||
getIsFaultyEarlyFlakeDetection | ||
} | ||
@@ -577,1 +580,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,3 +14,5 @@ 'use strict' | ||
const dogstatsd = require('./dogstatsd') | ||
const NoopDogStatsDClient = require('./noop/dogstatsd') | ||
const spanleak = require('./spanleak') | ||
const { SSITelemetry } = require('./profiling/ssi-telemetry') | ||
@@ -24,3 +26,3 @@ class Tracer extends NoopProxy { | ||
this._pluginManager = new PluginManager(this) | ||
this.dogstatsd = new dogstatsd.NoopDogStatsDClient() | ||
this.dogstatsd = new NoopDogStatsDClient() | ||
this._tracingInitialized = false | ||
@@ -77,2 +79,4 @@ } | ||
const ssiTelemetry = new SSITelemetry() | ||
ssiTelemetry.start() | ||
if (config.profiling.enabled) { | ||
@@ -86,2 +90,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) | ||
} | ||
@@ -88,0 +94,0 @@ if (!this._profilerStarted) { |
@@ -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
1743856
528
50502
154
+ 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