Skip to content

Add block-outcome telemetry for Netty blocking enforcement failures - #12316

Open
jandro996 wants to merge 3 commits into
masterfrom
APPSEC-62696
Open

Add block-outcome telemetry for Netty blocking enforcement failures#12316
jandro996 wants to merge 3 commits into
masterfrom
APPSEC-62696

Conversation

@jandro996

@jandro996 jandro996 commented Aug 27, 2026

Copy link
Copy Markdown
Member

What Does This Do

  • Adds void reportBlockFailure(); to AppSecContext (internal-api), alongside isManuallyKept().
  • Implements reportBlockFailure() in AppSecRequestContext by delegating to the existing setWafRequestBlockFailure() volatile field — no new state added.
  • Wires NettyMultipartHelper#tryBlock(): captures the boolean returned by BlockResponseFunction#tryCommitBlockingResponse(...); on false, resolves AppSecContext via ctx.getData(RequestContextSlot.APPSEC) (the canonical instanceof pattern already used by LambdaAppSecHandler) and calls reportBlockFailure(). The method still throws BlockingException unconditionally, unchanged.
  • Makes NettyBlockResponseFunction#tryCommitBlockingResponse() idempotent per request: a single request can trigger multiple blocking evaluations (e.g. one tryBlock() call per multipart chunk in HttpPostRequestDecoderInstrumentation's advice). Once an earlier call has already committed the block successfully, ServerRequestContext.isPending() legitimately turns false for the request — without this guard, a later call would misread that as a commit failure and report a spurious block_failure for a block that actually succeeded.
  • Adds a one-line comment at MaybeBlockResponseHandler#write()'s writeAndFlush listener flagging the async post-commit write-failure path as a known, currently-unreported gap for a future framework PR to pick up.
  • Adds test coverage:
    • A new case in WAFModuleSpecification.groovy asserting WafMetricCollector.raspRuleMatch(RuleType, boolean blocked) is called with the correct blocked value after RASP action processing.
    • NettyMultipartHelperBlockFailureTest.java (new JUnit 5 test) verifying reportBlockFailure() fires when tryCommitBlockingResponse returns false, and does NOT fire when it returns true.

Scope

This is the first PR of a per-framework rollout — only Netty is covered here. Other frameworks (Tomcat, Jetty, Vert.x, Undertow, Grizzly, Play, Akka-http, Ratpack, RESTEasy, Jersey, Liberty, Spring-webmvc, commons-fileupload, okhttp) are explicitly out of scope and will get their own follow-up PRs. The async post-commit write failure in MaybeBlockResponseHandler (channel write happens after the block decision, listener-driven) is also deliberately deferred — wiring it up requires investigating the ordering between span/request close and the channel listener to avoid introducing a race.

Motivation

appsec.waf.requests currently has no signal for when an AppSec block action was decided but its commit to the client actually failed (e.g. the response was already committed, or the channel write failed). This closes that gap for the synchronous Netty commit path, so failed block enforcement becomes visible in telemetry instead of silently looking like a successful block.

Additional Notes

None.

Contributor Checklist

Jira ticket: APPSEC-62696

Note: Once your PR is ready to merge, add it to the merge queue by commenting /merge. /merge -c cancels the queue request. /merge -f --reason "reason" skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.

Report failed AppSec block-response commits to WafMetricCollector so
appsec.waf.requests carries an accurate block_failure tag, scoped to
Netty as the first framework. AppSecContext gains a module-boundary-safe
reportBlockFailure() that AppSecRequestContext delegates to the existing
setWafRequestBlockFailure() field.
@jandro996 jandro996 added type: feature Enhancements and improvements inst: netty Netty instrumentation comp: asm waf Application Security Management (WAF) labels Aug 27, 2026
@jandro996

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c99b3ee39

ℹ️ 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".

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
Patch Coverage: 0.00%
Overall Coverage: 58.35% (-0.44%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 4a2bd4d | Docs | View more details | Give us feedback!

NettyBlockResponseFunction.tryCommitBlockingResponse() now tracks
whether a blocking response was already initiated for the current
request. HttpPostRequestDecoderInstrumentation's advice can invoke
tryBlock() multiple times across separate decoder invocations for the
same request (e.g. one per multipart chunk); once an earlier call
already committed the block successfully, ServerRequestContext.isPending()
returns false for later calls, which previously caused a spurious
block_failure to be reported even though the block had actually succeeded.
@jandro996

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: cdd1140d3d

ℹ️ 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".

@jandro996
jandro996 marked this pull request as ready for review August 27, 2026 13:22
@jandro996
jandro996 requested review from a team as code owners August 27, 2026 13:22
@jandro996
jandro996 requested review from claponcet, jordan-wong and manuel-alvarez-alvarez and removed request for a team August 27, 2026 13:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdd1140d3d

ℹ️ 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".

() ->
commitBlockingResponse(
segment, statusCode, templateType, extraHeaders, securityResponseId));
blockingResponseInitiated = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Set initiated only after the queued commit succeeds

When this method is called outside the channel's event loop and the queued commitBlockingResponse later returns false—for example, because the request ceased to be pending before the task ran or the required tracing handler is absent—this assignment still marks the block as initiated. The caller therefore receives true, subsequent attempts short-circuit at line 149, and NettyMultipartHelper neither retries nor reports block_failure. Fresh evidence in this revision is the new unconditional assignment after scheduling; update the state and failure telemetry from the queued task based on the actual commit result.

Useful? React with 👍 / 👎.

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datadog Autotest: FAIL

An off-event-loop block task can fail after Netty accepts it. The new flag still marks it as complete, so later block attempts return success without enforcement or failure telemetry.

Open Bits AI session

🤖 Datadog Autotest · Commit cdd1140 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

NettyBlockResponseFunction.tryCommitBlockingResponse() marked
blockingResponseInitiated = true immediately after scheduling the
off-event-loop commitBlockingResponse() call, without waiting for it
to actually run. If that async commit failed once executed, the
failure was silently swallowed and every later tryBlock() call for
the same request would short-circuit to true, hiding the failure
from block_failure telemetry. The flag is now set only inside the
scheduled task, after commitBlockingResponse() actually returns true,
matching the same-thread branch's existing behavior.
@jandro996

Copy link
Copy Markdown
Member Author

Good catch. Fixed in 4a2bd4d: the off-event-loop branch of NettyBlockResponseFunction#tryCommitBlockingResponse() was setting blockingResponseInitiated = true right after scheduling the async commit, not after it actually succeeded. If the scheduled commitBlockingResponse() failed once it ran on the event loop, that failure was silently swallowed and every subsequent tryBlock() call for the same request would short-circuit to true, hiding the failure from block_failure telemetry going forward. The flag is now set only inside the scheduled task, and only when commitBlockingResponse() actually returns true — matching what the same-thread branch already did.

@jandro996

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 4a2bd4db0e

ℹ️ 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".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: asm waf Application Security Management (WAF) inst: netty Netty instrumentation type: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant