Skip to content

Commit

Permalink
Add appsec propagation tag to other codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
jandro996 committed Jun 4, 2024
1 parent 9180a62 commit 59176d0
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
int tagPos = 0;
TagValue decisionMakerTagValue = null;
TagValue traceIdTagValue = null;
boolean appsecPropagationEnabled = false;
while (tagPos < len) {
int tagKeyEndsAt =
validateCharsUntilSeparatorOrEnd(
Expand Down Expand Up @@ -95,6 +96,8 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
decisionMakerTagValue = tagValue;
} else if (tagKey.equals(TRACE_ID_TAG)) {
traceIdTagValue = tagValue;
} else if (tagKey.equals(APPSEC_TAG)) {
appsecPropagationEnabled = true;
} else {
if (tagPairs == null) {
// This is roughly the size of a two element linked list but can hold six
Expand All @@ -107,7 +110,8 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
}
tagPos = tagValueEndsAt + 1;
}
return tagsFactory.createValid(tagPairs, decisionMakerTagValue, traceIdTagValue);
return tagsFactory.createValid(
tagPairs, decisionMakerTagValue, traceIdTagValue, appsecPropagationEnabled);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ protected static boolean validateTagValue(TagKey tagKey, TagValue tagValue) {
return false;
} else if (tagKey.equals(TRACE_ID_TAG) && !validateTraceId(tagValue)) {
return false;
} else if (tagKey.equals(APPSEC_TAG) && !validateAppsecTagValue(tagValue)) {
return false;
}
return true;
}
Expand Down Expand Up @@ -211,6 +213,10 @@ private static boolean validateTraceId(TagValue value) {
return true;
}

private static boolean validateAppsecTagValue(TagValue value) {
return value.length() == 1 && value.charAt(0) == '1';
}

protected static boolean isDigit(char c) {
return c >= '0' && c <= '9';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static datadog.trace.core.propagation.PropagationTags.HeaderType.DATADOG;
import static datadog.trace.core.propagation.PropagationTags.HeaderType.W3C;
import static datadog.trace.core.propagation.ptags.PTagsCodec.APPSEC_TAG;
import static datadog.trace.core.propagation.ptags.PTagsCodec.DECISION_MAKER_TAG;
import static datadog.trace.core.propagation.ptags.PTagsCodec.TRACE_ID_TAG;

Expand Down Expand Up @@ -45,7 +46,7 @@ PTagsCodec getDecoderEncoder(@Nonnull HeaderType headerType) {

@Override
public final PropagationTags empty() {
return createValid(null, null, null);
return createValid(null, null, null, false);
}

@Override
Expand All @@ -54,8 +55,12 @@ public final PropagationTags fromHeaderValue(@Nonnull HeaderType headerType, Str
}

PropagationTags createValid(
List<TagElement> tagPairs, TagValue decisionMakerTagValue, TagValue traceIdTagValue) {
return new PTags(this, tagPairs, decisionMakerTagValue, traceIdTagValue);
List<TagElement> tagPairs,
TagValue decisionMakerTagValue,
TagValue traceIdTagValue,
boolean appsecPropagationEnabled) {
return new PTags(
this, tagPairs, decisionMakerTagValue, traceIdTagValue, appsecPropagationEnabled);
}

PropagationTags createInvalid(String error) {
Expand Down Expand Up @@ -105,22 +110,32 @@ public PTags(
PTagsFactory factory,
List<TagElement> tagPairs,
TagValue decisionMakerTagValue,
TagValue traceIdTagValue) {
this(factory, tagPairs, decisionMakerTagValue, traceIdTagValue, PrioritySampling.UNSET, null);
TagValue traceIdTagValue,
boolean appsecPropagationEnabled) {
this(
factory,
tagPairs,
decisionMakerTagValue,
traceIdTagValue,
appsecPropagationEnabled,
PrioritySampling.UNSET,
null);
}

PTags(
PTagsFactory factory,
List<TagElement> tagPairs,
TagValue decisionMakerTagValue,
TagValue traceIdTagValue,
boolean appsecPropagationEnabled,
int samplingPriority,
CharSequence origin) {
assert tagPairs == null || tagPairs.size() % 2 == 0;
this.factory = factory;
this.tagPairs = tagPairs;
this.canChangeDecisionMaker = decisionMakerTagValue == null;
this.decisionMakerTagValue = decisionMakerTagValue;
this.appsecPropagationEnabled = appsecPropagationEnabled;
this.samplingPriority = samplingPriority;
this.origin = origin;
if (traceIdTagValue != null) {
Expand All @@ -134,7 +149,7 @@ public PTags(
}

static PTags withError(PTagsFactory factory, String error) {
PTags pTags = new PTags(factory, null, null, null, PrioritySampling.UNSET, null);
PTags pTags = new PTags(factory, null, null, null, false, PrioritySampling.UNSET, null);
pTags.error = error;
return pTags;
}
Expand Down Expand Up @@ -304,6 +319,9 @@ int getXDatadogTagsSize() {
size = PTagsCodec.calcXDatadogTagsSize(getTagPairs());
size = PTagsCodec.calcXDatadogTagsSize(size, DECISION_MAKER_TAG, decisionMakerTagValue);
size = PTagsCodec.calcXDatadogTagsSize(size, TRACE_ID_TAG, traceIdHighOrderBitsHexTagValue);
if (appsecPropagationEnabled) {
size = PTagsCodec.calcXDatadogTagsSize(size, APPSEC_TAG, TagValue.from("1"));
}
xDatadogTagsSize = size;
}
return size;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
CharSequence origin = null;
TagValue decisionMakerTagValue = null;
TagValue traceIdTagValue = null;
boolean appsecPropagationEnabled = false;
int maxUnknownSize = 0;
while (tagPos < ddMemberValueEnd) {
int tagKeyEndsAt =
Expand Down Expand Up @@ -145,6 +146,8 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
decisionMakerTagValue = tagValue;
} else if (tagKey.equals(TRACE_ID_TAG)) {
traceIdTagValue = tagValue;
} else if (tagKey.equals(APPSEC_TAG)) {
appsecPropagationEnabled = true;
} else {
if (tagPairs == null) {
// This is roughly the size of a two element linked list but can hold six
Expand Down Expand Up @@ -176,6 +179,7 @@ PropagationTags fromHeaderValue(PTagsFactory tagsFactory, String value) {
tagPairs,
decisionMakerTagValue,
traceIdTagValue,
appsecPropagationEnabled,
samplingPriority,
origin,
value,
Expand Down Expand Up @@ -686,6 +690,7 @@ private static W3CPTags empty(
null,
null,
null,
false,
PrioritySampling.UNSET,
null,
original,
Expand Down Expand Up @@ -716,14 +721,22 @@ public W3CPTags(
List<TagElement> tagPairs,
TagValue decisionMakerTagValue,
TagValue traceIdTagValue,
boolean appsecPropagationEnabled,
int samplingPriority,
CharSequence origin,
String original,
int firstMemberStart,
int ddMemberStart,
int ddMemberValueEnd,
int maxUnknownSize) {
super(factory, tagPairs, decisionMakerTagValue, traceIdTagValue, samplingPriority, origin);
super(
factory,
tagPairs,
decisionMakerTagValue,
traceIdTagValue,
appsecPropagationEnabled,
samplingPriority,
origin);
this.tracestate = original;
this.firstMemberStart = firstMemberStart;
this.ddMemberStart = ddMemberStart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class DatadogPropagationTagsTest extends DDCoreSpecification {
"_dd.p.tid=123456789ABCDEF0" | null | ["_dd.propagation_error": "malformed_tid 123456789ABCDEF0"] // invalid tid tag value: upper-case characters
"_dd.p.tid=123456789abcdefg" | null | ["_dd.propagation_error": "malformed_tid 123456789abcdefg"] // invalid tid tag value: non-hexadecimal characters
"_dd.p.tid=-123456789abcdef" | null | ["_dd.propagation_error": "malformed_tid -123456789abcdef"] // invalid tid tag value: non-hexadecimal characters
"_dd.p.appsec=1" | "_dd.p.appsec=1" | ["_dd.p.appsec": "1"]
}

def "datadog propagation tags should translate to w3c tags #headerValue"() {
Expand All @@ -91,6 +92,7 @@ class DatadogPropagationTagsTest extends DDCoreSpecification {
headerValue | expectedHeaderValue | tags
'_dd.p.dm=934086a686-4' | 'dd=t.dm:934086a686-4' | ['_dd.p.dm': '934086a686-4']
'_dd.p.dm=934086a686-4,_dd.p.f=w00t==' | 'dd=t.dm:934086a686-4;t.f:w00t~~' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t==']
'_dd.p.appsec=1' | 'dd=t.appsec:1' | ['_dd.p.appsec': '1']
}

def "update propagation tags sampling mechanism #originalTagSet"() {
Expand Down Expand Up @@ -134,6 +136,29 @@ class DatadogPropagationTagsTest extends DDCoreSpecification {
",_dd.p.dm=Value" | SAMPLER_KEEP | AGENT_RATE | "_dd.p.dm=-1" | ["_dd.propagation_error": "decoding_error", "_dd.p.dm": "-1"]
}

def "update propagation tags appsec propagation #originalTagSet"() {
setup:
def config = Mock(Config)
config.getxDatadogTagsMaxLength() >> 512
def propagationTagsFactory = PropagationTags.factory(config)
def propagationTags = propagationTagsFactory.fromHeaderValue(PropagationTags.HeaderType.DATADOG, originalTagSet)

when:
propagationTags.updateAppsecPropagation(enabled)

then:
propagationTags.headerValue(PropagationTags.HeaderType.DATADOG) == expectedHeaderValue
propagationTags.createTagMap() == tags

where:
originalTagSet | enabled | expectedHeaderValue | tags
// keep the existing dm tag as is
"_dd.p.appsec=1" | true | "_dd.p.appsec=1" | ["_dd.p.appsec": "1"]
"" | false | null | [:]
//Invalid input
"_dd.p.appsec=0" | false | null | ["_dd.propagation_error": "decoding_error"]
}

def extractionLimitExceeded() {
setup:
def tags = "_dd.p.anytag=value"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ class W3CPropagationTagsTest extends DDCoreSpecification {
null | null | [:]
'' | null | [:]
'dd=s:0;t.dm:934086a686-4' | 'dd=s:0;t.dm:934086a686-4' | ['_dd.p.dm': '934086a686-4']
'dd=s:0;t.appsec:1' | 'dd=s:0;t.appsec:1' | ['_dd.p.appsec': '1']
'dd=s:0;t.dm:934086a686-4;t.appsec:1' | 'dd=s:0;t.dm:934086a686-4;t.appsec:1' | ['_dd.p.dm': '934086a686-4', '_dd.p.appsec': '1']
'other=whatever,dd=s:0;t.dm:934086a686-4' | 'dd=s:0;t.dm:934086a686-4,other=whatever' | ['_dd.p.dm': '934086a686-4']
'dd=s:0;t.dm:934086a687-3,other=whatever' | 'dd=s:0;t.dm:934086a687-3,other=whatever' | ['_dd.p.dm': '934086a687-3']
'some=thing,dd=s:0;t.dm:934086a687-3,other=whatever' | 'dd=s:0;t.dm:934086a687-3,some=thing,other=whatever' | ['_dd.p.dm': '934086a687-3']
Expand Down Expand Up @@ -278,6 +280,8 @@ class W3CPropagationTagsTest extends DDCoreSpecification {
headerValue | expectedHeaderValue | tags
'dd=s:0;t.dm:934086a686-4' | '_dd.p.dm=934086a686-4' | ['_dd.p.dm': '934086a686-4']
'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~' | '_dd.p.dm=934086a686-4,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t==']
'dd=s:0;t.appsec:1' | '_dd.p.appsec=1' | ['_dd.p.appsec': '1']
'other=whatever,dd=s:0;t.dm:934086a686-4;t.f:w00t~~;t.appsec:1' | '_dd.p.dm=934086a686-4,_dd.p.appsec=1,_dd.p.f=w00t==' | ['_dd.p.dm': '934086a686-4', '_dd.p.f': 'w00t==', '_dd.p.appsec': '1']
'some=thing,other=whatever' | null | [:]
}

Expand Down Expand Up @@ -310,6 +314,31 @@ class W3CPropagationTagsTest extends DDCoreSpecification {
'dd=s:1;o:some;t.dm:934086a686-4' | PrioritySampling.SAMPLER_DROP | SamplingMechanism.EXTERNAL_OVERRIDE | "other" | 'dd=s:0;o:other' | [:]
}

def "propagation tags should be updated by appsec propagation #appsec"() {
setup:
def config = Mock(Config)
config.getxDatadogTagsMaxLength() >> 512
def propagationTagsFactory = PropagationTags.factory(config)

when:
def propagationTags = propagationTagsFactory.fromHeaderValue(HeaderType.W3C, headerValue)

then:
propagationTags.headerValue(HeaderType.W3C) != expectedHeaderValue

when:
propagationTags.updateAppsecPropagation(appsec)

then:
propagationTags.headerValue(HeaderType.W3C) == expectedHeaderValue
propagationTags.createTagMap() == tags

where:
headerValue | appsec | expectedHeaderValue | tags
'dd=t.appsec:1;x:unknown' | false | 'dd=x:unknown' | [:]
'dd=x:unknown' | true | 'dd=t.appsec:1;x:unknown' | ['_dd.p.appsec': '1']
}

static private String toLcAlpha(String cs) {
// Argh groovy and characters
char c = cs
Expand Down

0 comments on commit 59176d0

Please sign in to comment.