[AAP] Add response headers even if no appsec event is present#8784
Conversation
BenchmarksBenchmark execution time: 2026-06-29 18:41:57 Comparing candidate commit cdd3e06 in PR branch Found 0 performance improvements and 1 performance regressions! Performance is the same for 71 metrics, 0 unstable metrics, 61 known flaky benchmarks, 65 flaky benchmarks without significant changes.
|
This comment has been minimized.
This comment has been minimized.
fdeb404 to
74bf55d
Compare
|
@codex review |
74bf55d to
c4f484b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 74bf55dab4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| var headers = CanAccessHeaders ? _httpTransport.GetResponseHeaders() : new NameValueHeadersCollection(new NameValueCollection()); | ||
| AddHeaderTags(_span, headers, AlwaysResponseHeaders, SpanContextPropagator.HttpResponseHeadersTagPrefix); |
There was a problem hiding this comment.
Update snapshots for clean AppSec responses
When AppSec is enabled but the request is not an AppSec event, this new path now adds http.response.headers.content-type and http.response.headers.content-length to the span. The existing Security.AspNetCore5TraceTagging._.verified.txt snapshot still has the first two /Health spans (TraceTagging/v1 and TraceTagging/v2) without those tags, while the later event spans show that this endpoint does return both headers; since no verified snapshots were updated in this commit, AspNetCore5TraceTagging.TestTraceTaggingRules will fail snapshot verification.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
I assume this is fixed now @daniel-romano-DD?
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8784) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard. Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph). Duration chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (70ms) : 69, 72
master - mean (71ms) : 69, 72
section Bailout
This PR (8784) - mean (75ms) : 73, 76
master - mean (74ms) : 73, 76
section CallTarget+Inlining+NGEN
This PR (8784) - mean (1,087ms) : 1045, 1130
master - mean (1,085ms) : 1043, 1127
FakeDbCommand (.NET Core 3.1)gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (110ms) : 107, 113
master - mean (110ms) : 107, 113
section Bailout
This PR (8784) - mean (111ms) : 109, 113
master - mean (110ms) : 108, 112
section CallTarget+Inlining+NGEN
This PR (8784) - mean (780ms) : 762, 799
master - mean (780ms) : 753, 807
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (97ms) : 95, 100
master - mean (97ms) : 94, 99
section Bailout
This PR (8784) - mean (98ms) : 96, 100
master - mean (98ms) : 96, 101
section CallTarget+Inlining+NGEN
This PR (8784) - mean (939ms) : 894, 984
master - mean (937ms) : 899, 975
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (99ms) : 94, 105
master - mean (100ms) : 94, 106
section Bailout
This PR (8784) - mean (98ms) : 94, 102
master - mean (97ms) : 94, 100
section CallTarget+Inlining+NGEN
This PR (8784) - mean (813ms) : 778, 847
master - mean (814ms) : 770, 858
HttpMessageHandler (.NET Framework 4.8)gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (204ms) : 198, 210
master - mean (206ms) : 201, 212
section Bailout
This PR (8784) - mean (209ms) : 205, 212
master - mean (212ms) : 205, 219
section CallTarget+Inlining+NGEN
This PR (8784) - mean (1,240ms) : 1181, 1298
master - mean (1,231ms) : 1177, 1285
HttpMessageHandler (.NET Core 3.1)gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (295ms) : 288, 303
master - mean (297ms) : 292, 302
section Bailout
This PR (8784) - mean (299ms) : 288, 310
master - mean (297ms) : 292, 303
section CallTarget+Inlining+NGEN
This PR (8784) - mean (989ms) : 964, 1013
master - mean (988ms) : 969, 1007
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (291ms) : 282, 300
master - mean (290ms) : 283, 297
section Bailout
This PR (8784) - mean (289ms) : 280, 298
master - mean (290ms) : 285, 295
section CallTarget+Inlining+NGEN
This PR (8784) - mean (1,184ms) : 1137, 1231
master - mean (1,189ms) : 1153, 1224
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8784) - mean (287ms) : 279, 294
master - mean (287ms) : 282, 293
section Bailout
This PR (8784) - mean (287ms) : 280, 295
master - mean (287ms) : 282, 292
section CallTarget+Inlining+NGEN
This PR (8784) - mean (1,066ms) : 985, 1147
master - mean (1,055ms) : 1005, 1105
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c4f484b25e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Snapshots difference summaryThe following differences have been observed in committed snapshots. It is meant to help the reviewer. 4 occurrences of : + "http.response.headers.content-type": "text/plain; charset=utf-8",
2 occurrences of : + http.response.headers.content-length: 46,
+ http.response.headers.content-type: text/plain; charset=utf-8,
34 occurrences of : + http.response.headers.content-type: text/html; charset=utf-8,
1 occurrences of : + http.response.headers.content-length: 51,
+ http.response.headers.content-type: text/plain; charset=utf-8,
25 occurrences of : + http.response.headers.content-type: application/json; charset=utf-8,
4 occurrences of : + http.response.headers.content-length: 3,
+ http.response.headers.content-type: text/plain; charset=utf-8,
22 occurrences of : + http.response.headers.content-length: 0,
1 occurrences of : + http.response.headers.content-length: 18,
+ http.response.headers.content-type: text/plain; charset=utf-8,
1 occurrences of : + http.response.headers.content-length: 13,
+ http.response.headers.content-type: text/plain; charset=utf-8,
5 occurrences of : + http.response.headers.content-length: 49,
+ http.response.headers.content-type: text/plain; charset=utf-8,
2 occurrences of : + http.response.headers.content-length: 24,
+ http.response.headers.content-type: text/plain; charset=utf-8,
2 occurrences of : + http.response.headers.content-length: 4,
+ http.response.headers.content-type: application/json; charset=utf-8,
2 occurrences of : + http.response.headers.content-length: 35,
+ http.response.headers.content-type: application/json; charset=utf-8,
|
f177466 to
bd3d220
Compare
bd3d220 to
cd84915
Compare
cd84915 to
759f84b
Compare
| var headers = CanAccessHeaders ? _httpTransport.GetResponseHeaders() : new NameValueHeadersCollection(new NameValueCollection()); | ||
| AddHeaderTags(_span, headers, AlwaysResponseHeaders, SpanContextPropagator.HttpResponseHeadersTagPrefix); |
There was a problem hiding this comment.
I assume this is fixed now @daniel-romano-DD?
| return; | ||
| } | ||
|
|
||
| var headers = CanAccessHeaders ? _httpTransport.GetResponseHeaders() : new NameValueHeadersCollection(new NameValueCollection()); |
There was a problem hiding this comment.
If CanAccessHeaders == false, the chances are it always will be 🤔 And then we call new NameValueHeadersCollection() for every request...
Maybe we should update AddHeaderTags to take a null for headers, and bail out early in that scenario?
| settings.AddSimpleScrubber( | ||
| """http.response.headers.content-length: 0,""", | ||
| string.Empty); |
There was a problem hiding this comment.
You don't want this scrubber in .NET 8+? How come? 🤔
There was a problem hiding this comment.
FW is not sending the content lenght 0 header in newer versions
759f84b to
cdd3e06
Compare
Summary of changes
Always tag
http.response.headers.content-typeandhttp.response.headers.content-lengthon the root span when AppSec is enabled, regardless of whether a security event occurred.Reason for change
JIRA
These two headers are needed for accurate request characterisation in the backend (schema analysis, anomaly detection). Previously they were only emitted when the WAF produced a security event, leaving them absent on clean requests even when AppSec was enabled.
Implementation details
AlwaysResponseHeaders(containingcontent-typeandcontent-length) alongside the existingResponseHeadersdictionary inSecurityReporter.AddResponseHeadersToSpannow unconditionfrom the response and tags them. When asecurity event is present it falls through toAddResponseHeaderTagsas before, which tags all four response headers plus the endpoint tag.SecurityCoordinator.AddResponseHeadersToSpansimplified to delegate directly toReporter.AddResponseHeadersToSpanso both entry points share the same behaviour.Test coverage
Two new unit tests in
TraceTaggingResultTests:AddResponseHeadersToSpan_WithNoSecuriAndContentLength— assertscontent-typeandcontent-lengthare tagged when there is no security event, and thatcontent-encoding/content-languageareabsent.
AddResponseHeadersToSpan_WithSecurityEvent_AddsAllResponseHeaders— asserts all four response headers are tagged when the span is an AppSec event.Other details
N/A