dd-trace 3.20.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/index.d.ts +8 -1
  2. package/package.json +5 -4
  3. package/packages/datadog-instrumentations/src/grpc/client.js +9 -5
  4. package/packages/datadog-instrumentations/src/grpc/server.js +8 -4
  5. package/packages/datadog-instrumentations/src/helpers/register.js +4 -0
  6. package/packages/datadog-instrumentations/src/jest.js +20 -17
  7. package/packages/datadog-instrumentations/src/next.js +6 -1
  8. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -0
  9. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -1
  10. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +4 -2
  11. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +4 -3
  12. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -1
  13. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -0
  14. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -1
  15. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -1
  16. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +8 -1
  17. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -1
  18. package/packages/datadog-plugin-http/src/client.js +2 -1
  19. package/packages/datadog-plugin-http2/src/client.js +2 -1
  20. package/packages/datadog-plugin-jest/src/util.js +10 -1
  21. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +2 -1
  22. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +2 -1
  23. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +22 -5
  24. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +40 -4
  25. package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +2 -1
  26. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -1
  27. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  28. package/packages/dd-trace/src/appsec/iast/path-line.js +2 -1
  29. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +37 -0
  30. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +29 -0
  31. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +35 -0
  32. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +95 -0
  33. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +144 -0
  34. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +113 -0
  35. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +8 -0
  36. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -76
  37. package/packages/dd-trace/src/config.js +58 -8
  38. package/packages/dd-trace/src/constants.js +3 -1
  39. package/packages/dd-trace/src/git_metadata_tagger.js +17 -0
  40. package/packages/dd-trace/src/git_properties.js +32 -0
  41. package/packages/dd-trace/src/plugins/util/ci.js +62 -7
  42. package/packages/dd-trace/src/plugins/util/tags.js +5 -1
  43. package/packages/dd-trace/src/profiling/constants.js +0 -1
  44. package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
  45. package/packages/dd-trace/src/proxy.js +4 -0
  46. package/packages/dd-trace/src/serverless.js +25 -0
  47. package/packages/dd-trace/src/span_processor.js +3 -0
  48. package/packages/dd-trace/src/tracer.js +3 -2
  49. package/version.js +9 -0
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ const iastLog = require('../../../iast-log')
4
+
5
+ const COMMAND_PATTERN = '^(?:\\s*(?:sudo|doas)\\s+)?\\b\\S+\\b\\s(.*)'
6
+
7
+ class CommandSensitiveAnalyzer {
8
+ constructor () {
9
+ this._pattern = new RegExp(COMMAND_PATTERN, 'gmi')
10
+ }
11
+
12
+ extractSensitiveRanges (evidence) {
13
+ try {
14
+ this._pattern.lastIndex = 0
15
+
16
+ const regexResult = this._pattern.exec(evidence.value)
17
+ if (regexResult && regexResult.length > 1) {
18
+ const start = regexResult.index + (regexResult[0].length - regexResult[1].length)
19
+ const end = start + regexResult[1].length
20
+ return [{ start, end }]
21
+ }
22
+ } catch (e) {
23
+ iastLog.debug(e)
24
+ }
25
+ return []
26
+ }
27
+ }
28
+
29
+ module.exports = CommandSensitiveAnalyzer
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ const iastLog = require('../../../iast-log')
4
+
5
+ const LDAP_PATTERN = '\\(.*?(?:~=|=|<=|>=)(?<LITERAL>[^)]+)\\)'
6
+
7
+ class LdapSensitiveAnalyzer {
8
+ constructor () {
9
+ this._pattern = new RegExp(LDAP_PATTERN, 'gmi')
10
+ }
11
+
12
+ extractSensitiveRanges (evidence) {
13
+ try {
14
+ this._pattern.lastIndex = 0
15
+ const tokens = []
16
+
17
+ let regexResult = this._pattern.exec(evidence.value)
18
+ while (regexResult != null) {
19
+ if (!regexResult.groups.LITERAL) continue
20
+ // Computing indices manually since NodeJs 12 does not support d flag on regular expressions
21
+ // TODO Get indices from group by adding d flag in regular expression
22
+ const start = regexResult.index + (regexResult[0].length - regexResult.groups.LITERAL.length - 1)
23
+ const end = start + regexResult.groups.LITERAL.length
24
+ tokens.push({ start, end })
25
+ regexResult = this._pattern.exec(evidence.value)
26
+ }
27
+ return tokens
28
+ } catch (e) {
29
+ iastLog.debug(e)
30
+ }
31
+ return []
32
+ }
33
+ }
34
+
35
+ module.exports = LdapSensitiveAnalyzer
@@ -0,0 +1,95 @@
1
+ 'use strict'
2
+
3
+ const iastLog = require('../../../iast-log')
4
+
5
+ const STRING_LITERAL = '\'(?:\'\'|[^\'])*\''
6
+ const POSTGRESQL_ESCAPED_LITERAL = '\\$([^$]*)\\$.*?\\$\\1\\$'
7
+ const MYSQL_STRING_LITERAL = '"(?:\\\\"|[^"])*"|\'(?:\\\\\'|[^\'])*\''
8
+ const LINE_COMMENT = '--.*$'
9
+ const BLOCK_COMMENT = '/\\*[\\s\\S]*\\*/'
10
+ const EXPONENT = '(?:E[-+]?\\d+[fd]?)?'
11
+ const INTEGER_NUMBER = '(?<!\\w)\\d+'
12
+ const DECIMAL_NUMBER = '\\d*\\.\\d+'
13
+ const HEX_NUMBER = 'x\'[0-9a-f]+\'|0x[0-9a-f]+'
14
+ const BIN_NUMBER = 'b\'[0-9a-f]+\'|0b[0-9a-f]+'
15
+ const NUMERIC_LITERAL =
16
+ `[-+]?(?:${
17
+ [
18
+ HEX_NUMBER,
19
+ BIN_NUMBER,
20
+ DECIMAL_NUMBER + EXPONENT,
21
+ INTEGER_NUMBER + EXPONENT
22
+ ].join('|')
23
+ })`
24
+
25
+ class SqlSensitiveAnalyzer {
26
+ constructor () {
27
+ this._patterns = {
28
+ MYSQL: new RegExp(
29
+ [
30
+ NUMERIC_LITERAL,
31
+ MYSQL_STRING_LITERAL,
32
+ LINE_COMMENT,
33
+ BLOCK_COMMENT
34
+ ].join('|'),
35
+ 'gmi'
36
+ ),
37
+ POSTGRES: new RegExp(
38
+ [
39
+ NUMERIC_LITERAL,
40
+ POSTGRESQL_ESCAPED_LITERAL,
41
+ STRING_LITERAL,
42
+ LINE_COMMENT,
43
+ BLOCK_COMMENT
44
+ ].join('|'),
45
+ 'gmi'
46
+ )
47
+ }
48
+ }
49
+
50
+ extractSensitiveRanges (evidence) {
51
+ try {
52
+ const pattern = this._patterns[evidence.dialect]
53
+ pattern.lastIndex = 0
54
+ const tokens = []
55
+
56
+ let regexResult = pattern.exec(evidence.value)
57
+ while (regexResult != null) {
58
+ let start = regexResult.index
59
+ let end = regexResult.index + regexResult[0].length
60
+ const startChar = evidence.value.charAt(start)
61
+ if (startChar === '\'' || startChar === '"') {
62
+ start++
63
+ end--
64
+ } else if (end > start + 1) {
65
+ const nextChar = evidence.value.charAt(start + 1)
66
+ if (startChar === '/' && nextChar === '*') {
67
+ start += 2
68
+ end -= 2
69
+ } else if (startChar === '-' && startChar === nextChar) {
70
+ start += 2
71
+ } else if (startChar.toLowerCase() === 'q' && nextChar === '\'') {
72
+ start += 3
73
+ end -= 2
74
+ } else if (startChar === '$') {
75
+ const match = regexResult[0]
76
+ const size = match.indexOf('$', 1) + 1
77
+ if (size > 1) {
78
+ start += size
79
+ end -= size
80
+ }
81
+ }
82
+ }
83
+
84
+ tokens.push({ start, end })
85
+ regexResult = pattern.exec(evidence.value)
86
+ }
87
+ return tokens
88
+ } catch (e) {
89
+ iastLog.debug(e)
90
+ }
91
+ return []
92
+ }
93
+ }
94
+
95
+ module.exports = SqlSensitiveAnalyzer
@@ -0,0 +1,144 @@
1
+ 'use strict'
2
+
3
+ const vulnerabilities = require('../../vulnerabilities')
4
+
5
+ const { contains, intersects, remove } = require('./range-utils')
6
+
7
+ const CommandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
8
+ const LdapSensitiveAnalyzer = require('./sensitive-analyzers/ldap-sensitive-analyzer')
9
+ const SqlSensitiveAnalyzer = require('./sensitive-analyzers/sql-sensitive-analyzer')
10
+
11
+ // eslint-disable-next-line max-len
12
+ const DEFAULT_IAST_REDACTION_NAME_PATTERN = '(?: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)?)'
13
+ // eslint-disable-next-line max-len
14
+ const DEFAULT_IAST_REDACTION_VALUE_PATTERN = '(?:bearer\\s+[a-z0-9\\._\\-]+|glpat-[\\w\\-]{20}|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[\\-]{5}|ssh-rsa\\s*[a-z0-9/\\.+]{100,}))'
15
+
16
+ class SensitiveHandler {
17
+ constructor () {
18
+ this._namePattern = new RegExp(DEFAULT_IAST_REDACTION_NAME_PATTERN, 'gmi')
19
+ this._valuePattern = new RegExp(DEFAULT_IAST_REDACTION_VALUE_PATTERN, 'gmi')
20
+
21
+ this._sensitiveAnalyzers = new Map()
22
+ this._sensitiveAnalyzers.set(vulnerabilities.COMMAND_INJECTION, new CommandSensitiveAnalyzer())
23
+ this._sensitiveAnalyzers.set(vulnerabilities.LDAP_INJECTION, new LdapSensitiveAnalyzer())
24
+ this._sensitiveAnalyzers.set(vulnerabilities.SQL_INJECTION, new SqlSensitiveAnalyzer())
25
+ }
26
+
27
+ isSensibleName (name) {
28
+ this._namePattern.lastIndex = 0
29
+ return this._namePattern.test(name)
30
+ }
31
+
32
+ isSensibleValue (value) {
33
+ this._valuePattern.lastIndex = 0
34
+ return this._valuePattern.test(value)
35
+ }
36
+
37
+ isSensibleSource (source) {
38
+ return source != null && (this.isSensibleName(source.name) || this.isSensibleValue(source.value))
39
+ }
40
+
41
+ scrubEvidence (vulnerabilityType, evidence, sourcesIndexes, sources) {
42
+ const sensitiveAnalyzer = this._sensitiveAnalyzers.get(vulnerabilityType)
43
+ if (sensitiveAnalyzer) {
44
+ const sensitiveRanges = sensitiveAnalyzer.extractSensitiveRanges(evidence)
45
+ return this.toRedactedJson(evidence, sensitiveRanges, sourcesIndexes, sources)
46
+ }
47
+ return null
48
+ }
49
+
50
+ toRedactedJson (evidence, sensitive, sourcesIndexes, sources) {
51
+ const valueParts = []
52
+ const redactedSources = []
53
+
54
+ const { value, ranges } = evidence
55
+
56
+ let start = 0
57
+ let nextTaintedIndex = 0
58
+ let sourceIndex
59
+
60
+ let nextTainted = ranges.shift()
61
+ let nextSensitive = sensitive.shift()
62
+
63
+ for (let i = 0; i < value.length; i++) {
64
+ if (nextTainted != null && nextTainted.start === i) {
65
+ this.writeValuePart(valueParts, value.substring(start, i), sourceIndex)
66
+
67
+ sourceIndex = sourcesIndexes[nextTaintedIndex]
68
+
69
+ while (nextSensitive != null && contains(nextTainted, nextSensitive)) {
70
+ sourceIndex != null && redactedSources.push(sourceIndex)
71
+ nextSensitive = sensitive.shift()
72
+ }
73
+
74
+ if (nextSensitive != null && intersects(nextSensitive, nextTainted)) {
75
+ sourceIndex != null && redactedSources.push(sourceIndex)
76
+
77
+ const entries = remove(nextSensitive, nextTainted)
78
+ nextSensitive = entries.length > 0 ? entries[0] : null
79
+ }
80
+
81
+ this.isSensibleSource(sources[sourceIndex]) && redactedSources.push(sourceIndex)
82
+
83
+ if (redactedSources.indexOf(sourceIndex) > -1) {
84
+ this.writeRedactedValuePart(valueParts, sourceIndex)
85
+ } else {
86
+ const substringEnd = Math.min(nextTainted.end, value.length)
87
+ this.writeValuePart(valueParts, value.substring(nextTainted.start, substringEnd), sourceIndex)
88
+ }
89
+
90
+ start = i + (nextTainted.end - nextTainted.start)
91
+ i = start - 1
92
+ nextTainted = ranges.shift()
93
+ nextTaintedIndex++
94
+ sourceIndex = null
95
+ } else if (nextSensitive != null && nextSensitive.start === i) {
96
+ this.writeValuePart(valueParts, value.substring(start, i), sourceIndex)
97
+ if (nextTainted != null && intersects(nextSensitive, nextTainted)) {
98
+ sourceIndex = sourcesIndexes[nextTaintedIndex]
99
+ sourceIndex != null && redactedSources.push(sourceIndex)
100
+
101
+ for (const entry of remove(nextSensitive, nextTainted)) {
102
+ if (entry.start === i) {
103
+ nextSensitive = entry
104
+ } else {
105
+ sensitive.push(entry)
106
+ }
107
+ }
108
+ }
109
+
110
+ this.writeRedactedValuePart(valueParts)
111
+
112
+ start = i + (nextSensitive.end - nextSensitive.start)
113
+ i = start - 1
114
+ nextSensitive = sensitive.shift()
115
+ }
116
+ }
117
+
118
+ if (start < value.length) {
119
+ this.writeValuePart(valueParts, value.substring(start))
120
+ }
121
+
122
+ return { redactedValueParts: valueParts, redactedSources }
123
+ }
124
+
125
+ writeValuePart (valueParts, value, source) {
126
+ if (value.length > 0) {
127
+ if (source != null) {
128
+ valueParts.push({ value, source })
129
+ } else {
130
+ valueParts.push({ value })
131
+ }
132
+ }
133
+ }
134
+
135
+ writeRedactedValuePart (valueParts, source) {
136
+ if (source != null) {
137
+ valueParts.push({ redacted: true, source })
138
+ } else {
139
+ valueParts.push({ redacted: true })
140
+ }
141
+ }
142
+ }
143
+
144
+ module.exports = new SensitiveHandler()
@@ -0,0 +1,113 @@
1
+ const sensitiveHandler = require('./evidence-redaction/sensitive-handler')
2
+
3
+ class VulnerabilityFormatter {
4
+ constructor () {
5
+ this._redactVulnearbilities = true
6
+ }
7
+
8
+ setRedactVulnerabilities (shouldRedactVulnerabilities) {
9
+ this._redactVulnearbilities = shouldRedactVulnerabilities
10
+ }
11
+
12
+ extractSourcesFromVulnerability (vulnerability) {
13
+ if (!vulnerability.evidence.ranges) {
14
+ return []
15
+ }
16
+ return vulnerability.evidence.ranges.map(range => (
17
+ {
18
+ origin: range.iinfo.type,
19
+ name: range.iinfo.parameterName,
20
+ value: range.iinfo.parameterValue
21
+ }
22
+ ))
23
+ }
24
+
25
+ getRedactedValueParts (type, evidence, sourcesIndexes, sources) {
26
+ const scrubbingResult = sensitiveHandler.scrubEvidence(type, evidence, sourcesIndexes, sources)
27
+ if (scrubbingResult) {
28
+ const { redactedValueParts, redactedSources } = scrubbingResult
29
+ redactedSources.forEach(i => {
30
+ delete sources[i].value
31
+ sources[i].redacted = true
32
+ })
33
+ return { valueParts: redactedValueParts }
34
+ }
35
+
36
+ return this.getUnredactedValueParts(evidence, sourcesIndexes)
37
+ }
38
+
39
+ getUnredactedValueParts (evidence, sourcesIndexes) {
40
+ const valueParts = []
41
+ let fromIndex = 0
42
+ evidence.ranges.forEach((range, rangeIndex) => {
43
+ if (fromIndex < range.start) {
44
+ valueParts.push({ value: evidence.value.substring(fromIndex, range.start) })
45
+ }
46
+ valueParts.push({ value: evidence.value.substring(range.start, range.end), source: sourcesIndexes[rangeIndex] })
47
+ fromIndex = range.end
48
+ })
49
+ if (fromIndex < evidence.value.length) {
50
+ valueParts.push({ value: evidence.value.substring(fromIndex) })
51
+ }
52
+ return { valueParts }
53
+ }
54
+
55
+ formatEvidence (type, evidence, sourcesIndexes, sources) {
56
+ if (!evidence.ranges) {
57
+ return { value: evidence.value }
58
+ }
59
+
60
+ return this._redactVulnearbilities
61
+ ? this.getRedactedValueParts(type, evidence, sourcesIndexes, sources)
62
+ : this.getUnredactedValueParts(evidence, sourcesIndexes)
63
+ }
64
+
65
+ formatVulnerability (vulnerability, sourcesIndexes, sources) {
66
+ const formattedVulnerability = {
67
+ type: vulnerability.type,
68
+ hash: vulnerability.hash,
69
+ evidence: this.formatEvidence(vulnerability.type, vulnerability.evidence, sourcesIndexes, sources),
70
+ location: {
71
+ spanId: vulnerability.location.spanId
72
+ }
73
+ }
74
+ if (vulnerability.location.path) {
75
+ formattedVulnerability.location.path = vulnerability.location.path
76
+ }
77
+ if (vulnerability.location.line) {
78
+ formattedVulnerability.location.line = vulnerability.location.line
79
+ }
80
+ return formattedVulnerability
81
+ }
82
+
83
+ toJson (vulnerabilitiesToFormat) {
84
+ const sources = []
85
+
86
+ const vulnerabilities = vulnerabilitiesToFormat.map(vulnerability => {
87
+ const vulnerabilitySources = this.extractSourcesFromVulnerability(vulnerability)
88
+ const sourcesIndexes = []
89
+ vulnerabilitySources.forEach((source) => {
90
+ let sourceIndex = sources.findIndex(
91
+ existingSource =>
92
+ existingSource.origin === source.origin &&
93
+ existingSource.name === source.name &&
94
+ existingSource.value === source.value
95
+ )
96
+ if (sourceIndex === -1) {
97
+ sourceIndex = sources.length
98
+ sources.push(source)
99
+ }
100
+ sourcesIndexes.push(sourceIndex)
101
+ })
102
+
103
+ return this.formatVulnerability(vulnerability, sourcesIndexes, sources)
104
+ })
105
+
106
+ return {
107
+ sources,
108
+ vulnerabilities
109
+ }
110
+ }
111
+ }
112
+
113
+ module.exports = new VulnerabilityFormatter()
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ WEAK_HASH: 'WEAK_HASH',
3
+ WEAK_CIPHER: 'WEAK_CIPHER',
4
+ SQL_INJECTION: 'SQL_INJECTION',
5
+ PATH_TRAVERSAL: 'PATH_TRAVERSAL',
6
+ COMMAND_INJECTION: 'COMMAND_INJECTION',
7
+ LDAP_INJECTION: 'LDAP_INJECTION'
8
+ }
@@ -1,5 +1,6 @@
1
1
  const { MANUAL_KEEP } = require('../../../../../ext/tags')
2
2
  const LRU = require('lru-cache')
3
+ const vulnerabilitiesFormatter = require('./vulnerabilities-formatter')
3
4
  const VULNERABILITIES_KEY = 'vulnerabilities'
4
5
  const IAST_JSON_TAG_KEY = '_dd.iast.json'
5
6
  const VULNERABILITY_HASHES_MAX_SIZE = 1000
@@ -60,57 +61,6 @@ function isValidVulnerability (vulnerability) {
60
61
  vulnerability.location && vulnerability.location.spanId
61
62
  }
62
63
 
63
- function formatEvidence (evidence, sourcesIndexes) {
64
- if (!evidence.ranges) {
65
- return { value: evidence.value }
66
- }
67
-
68
- const valueParts = []
69
- let fromIndex = 0
70
- evidence.ranges.forEach((range, rangeIndex) => {
71
- if (fromIndex < range.start) {
72
- valueParts.push({ value: evidence.value.substring(fromIndex, range.start) })
73
- }
74
- valueParts.push({ value: evidence.value.substring(range.start, range.end), source: sourcesIndexes[rangeIndex] })
75
- fromIndex = range.end
76
- })
77
- if (fromIndex < evidence.value.length) {
78
- valueParts.push({ value: evidence.value.substring(fromIndex) })
79
- }
80
- return { valueParts }
81
- }
82
-
83
- function extractSourcesFromVulnerability (vulnerability) {
84
- if (!vulnerability.evidence.ranges) {
85
- return []
86
- }
87
- return vulnerability.evidence.ranges.map(range => (
88
- {
89
- origin: range.iinfo.type,
90
- name: range.iinfo.parameterName,
91
- value: range.iinfo.parameterValue
92
- }
93
- ))
94
- }
95
-
96
- function jsonVulnerabilityFromVulnerability (vulnerability, sourcesIndexes) {
97
- const jsonVulnerability = {
98
- type: vulnerability.type,
99
- hash: vulnerability.hash,
100
- evidence: formatEvidence(vulnerability.evidence, sourcesIndexes),
101
- location: {
102
- spanId: vulnerability.location.spanId
103
- }
104
- }
105
- if (vulnerability.location.path) {
106
- jsonVulnerability.location.path = vulnerability.location.path
107
- }
108
- if (vulnerability.location.line) {
109
- jsonVulnerability.location.line = vulnerability.location.line
110
- }
111
- return jsonVulnerability
112
- }
113
-
114
64
  function sendVulnerabilities (vulnerabilities, rootSpan) {
115
65
  if (vulnerabilities && vulnerabilities.length) {
116
66
  let span = rootSpan
@@ -124,31 +74,8 @@ function sendVulnerabilities (vulnerabilities, rootSpan) {
124
74
  }
125
75
 
126
76
  if (span && span.addTags) {
127
- const jsonToSend = {
128
- sources: [],
129
- vulnerabilities: []
130
- }
131
-
132
- deduplicateVulnerabilities(vulnerabilities).forEach((vulnerability) => {
133
- if (isValidVulnerability(vulnerability)) {
134
- const sourcesIndexes = []
135
- const vulnerabilitySources = extractSourcesFromVulnerability(vulnerability)
136
- vulnerabilitySources.forEach((source) => {
137
- let sourceIndex = jsonToSend.sources.findIndex(
138
- existingSource =>
139
- existingSource.origin === source.origin &&
140
- existingSource.name === source.name &&
141
- existingSource.value === source.value
142
- )
143
- if (sourceIndex === -1) {
144
- sourceIndex = jsonToSend.sources.length
145
- jsonToSend.sources.push(source)
146
- }
147
- sourcesIndexes.push(sourceIndex)
148
- })
149
- jsonToSend.vulnerabilities.push(jsonVulnerabilityFromVulnerability(vulnerability, sourcesIndexes))
150
- }
151
- })
77
+ const validAndDedupVulnerabilities = deduplicateVulnerabilities(vulnerabilities).filter(isValidVulnerability)
78
+ const jsonToSend = vulnerabilitiesFormatter.toJson(validAndDedupVulnerabilities)
152
79
 
153
80
  if (jsonToSend.vulnerabilities.length > 0) {
154
81
  const tags = {}
@@ -194,6 +121,7 @@ function deduplicateVulnerabilities (vulnerabilities) {
194
121
 
195
122
  function start (config, _tracer) {
196
123
  deduplicationEnabled = config.iast.deduplicationEnabled
124
+ vulnerabilitiesFormatter.setRedactVulnerabilities(config.iast.redactionEnabled)
197
125
  if (deduplicationEnabled) {
198
126
  startClearCacheTimer()
199
127
  }
@@ -2,13 +2,15 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const os = require('os')
5
+ const uuid = require('crypto-randomuuid')
5
6
  const URL = require('url').URL
6
7
  const log = require('./log')
7
8
  const pkg = require('./pkg')
8
9
  const coalesce = require('koalas')
9
10
  const tagger = require('./tagger')
10
11
  const { isTrue, isFalse } = require('./util')
11
- const uuid = require('crypto-randomuuid')
12
+ const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
13
+ const { getGitMetadataFromGitProperties } = require('./git_properties')
12
14
 
13
15
  const fromEntries = Object.fromEntries || (entries =>
14
16
  entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
@@ -159,6 +161,8 @@ class Config {
159
161
  process.env.DD_SERVICE_NAME ||
160
162
  this.tags.service ||
161
163
  process.env.AWS_LAMBDA_FUNCTION_NAME ||
164
+ process.env.FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
165
+ process.env.K_SERVICE || // Google Cloud Function Name set by newer runtimes
162
166
  pkg.name ||
163
167
  'node'
164
168
  const DD_SERVICE_MAPPING = coalesce(
@@ -183,9 +187,18 @@ class Config {
183
187
  process.env.DD_TRACE_STARTUP_LOGS,
184
188
  false
185
189
  )
190
+
191
+ const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
192
+
193
+ const isDeprecatedGCPFunction = process.env.FUNCTION_NAME !== undefined && process.env.GCP_PROJECT !== undefined
194
+ const isNewerGCPFunction = process.env.K_SERVICE !== undefined && process.env.FUNCTION_TARGET !== undefined
195
+ const isGCPFunction = isDeprecatedGCPFunction || isNewerGCPFunction
196
+
197
+ const inServerlessEnvironment = inAWSLambda || isGCPFunction
198
+
186
199
  const DD_TRACE_TELEMETRY_ENABLED = coalesce(
187
200
  process.env.DD_TRACE_TELEMETRY_ENABLED,
188
- !process.env.AWS_LAMBDA_FUNCTION_NAME
201
+ !inServerlessEnvironment
189
202
  )
190
203
  const DD_TELEMETRY_DEBUG_ENABLED = coalesce(
191
204
  process.env.DD_TELEMETRY_DEBUG_ENABLED,
@@ -269,7 +282,7 @@ class Config {
269
282
  const DD_TRACE_STATS_COMPUTATION_ENABLED = coalesce(
270
283
  options.stats,
271
284
  process.env.DD_TRACE_STATS_COMPUTATION_ENABLED,
272
- false
285
+ isGCPFunction
273
286
  )
274
287
 
275
288
  const DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = coalesce(
@@ -336,12 +349,10 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
336
349
  maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
337
350
  )
338
351
 
339
- const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
340
-
341
352
  const remoteConfigOptions = options.remoteConfig || {}
342
353
  const DD_REMOTE_CONFIGURATION_ENABLED = coalesce(
343
354
  process.env.DD_REMOTE_CONFIGURATION_ENABLED && isTrue(process.env.DD_REMOTE_CONFIGURATION_ENABLED),
344
- !inAWSLambda
355
+ !inServerlessEnvironment
345
356
  )
346
357
  const DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS = coalesce(
347
358
  parseInt(remoteConfigOptions.pollInterval),
@@ -388,11 +399,22 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
388
399
  true
389
400
  )
390
401
 
402
+ const DD_IAST_REDACTION_ENABLED = coalesce(
403
+ iastOptions && iastOptions.redactionEnabled,
404
+ !isFalse(process.env.DD_IAST_REDACTION_ENABLED),
405
+ true
406
+ )
407
+
391
408
  const DD_CIVISIBILITY_GIT_UPLOAD_ENABLED = coalesce(
392
409
  process.env.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED,
393
410
  true
394
411
  )
395
412
 
413
+ const DD_TRACE_GIT_METADATA_ENABLED = coalesce(
414
+ process.env.DD_TRACE_GIT_METADATA_ENABLED,
415
+ true
416
+ )
417
+
396
418
  const ingestion = options.ingestion || {}
397
419
  const dogstatsd = coalesce(options.dogstatsd, {})
398
420
  const sampler = {
@@ -424,7 +446,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
424
446
  })
425
447
  }
426
448
 
427
- const defaultFlushInterval = inAWSLambda ? 0 : 2000
449
+ const defaultFlushInterval = inServerlessEnvironment ? 0 : 2000
428
450
 
429
451
  this.tracing = !isFalse(DD_TRACING_ENABLED)
430
452
  this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
@@ -497,7 +519,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
497
519
  requestSampling: DD_IAST_REQUEST_SAMPLING,
498
520
  maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
499
521
  maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS,
500
- deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED
522
+ deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED,
523
+ redactionEnabled: DD_IAST_REDACTION_ENABLED
501
524
  }
502
525
 
503
526
  this.isCiVisibility = isTrue(DD_IS_CIVISIBILITY)
@@ -506,6 +529,31 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
506
529
  this.isGitUploadEnabled = this.isCiVisibility &&
507
530
  (this.isIntelligentTestRunnerEnabled && !isFalse(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
508
531
 
532
+ this.gitMetadataEnabled = isTrue(DD_TRACE_GIT_METADATA_ENABLED)
533
+
534
+ if (this.gitMetadataEnabled) {
535
+ this.repositoryUrl = coalesce(
536
+ process.env.DD_GIT_REPOSITORY_URL,
537
+ this.tags[GIT_REPOSITORY_URL]
538
+ )
539
+ this.commitSHA = coalesce(
540
+ process.env.DD_GIT_COMMIT_SHA,
541
+ this.tags[GIT_COMMIT_SHA]
542
+ )
543
+ if (!this.repositoryUrl || !this.commitSHA) {
544
+ const DD_GIT_PROPERTIES_FILE = coalesce(
545
+ process.env.DD_GIT_PROPERTIES_FILE,
546
+ `${process.cwd()}/git.properties`
547
+ )
548
+ const gitPropertiesString = maybeFile(DD_GIT_PROPERTIES_FILE)
549
+ if (gitPropertiesString) {
550
+ const { commitSHA, repositoryUrl } = getGitMetadataFromGitProperties(gitPropertiesString)
551
+ this.commitSHA = this.commitSHA || commitSHA
552
+ this.repositoryUrl = this.repositoryUrl || repositoryUrl
553
+ }
554
+ }
555
+ }
556
+
509
557
  this.stats = {
510
558
  enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
511
559
  }
@@ -513,6 +561,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
513
561
  this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
514
562
  this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
515
563
 
564
+ this.isGCPFunction = isGCPFunction
565
+
516
566
  tagger.add(this.tags, {
517
567
  service: this.service,
518
568
  env: this.env,
@@ -25,5 +25,7 @@ module.exports = {
25
25
  ERROR_MESSAGE: 'error.message',
26
26
  ERROR_STACK: 'error.stack',
27
27
  COMPONENT: 'component',
28
- CLIENT_PORT_KEY: 'network.destination.port'
28
+ CLIENT_PORT_KEY: 'network.destination.port',
29
+ SCI_REPOSITORY_URL: '_dd.git.repository_url',
30
+ SCI_COMMIT_SHA: '_dd.git.commit.sha'
29
31
  }