Skip to content

fix(appsec): suppress informational responses after blocking requests#9290

Merged
pabloerhard merged 6 commits into
masterfrom
pabloerhard/fix-test-swallowing
Jul 13, 2026
Merged

fix(appsec): suppress informational responses after blocking requests#9290
pabloerhard merged 6 commits into
masterfrom
pabloerhard/fix-test-swallowing

Conversation

@pabloerhard

@pabloerhard pabloerhard commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes AppSec request blocking so applications cannot emit an HTTP informational response after AppSec has already blocked the request.

The HTTP server instrumentation now wraps ServerResponse.writeContinue(), writeProcessing(), and writeEarlyHints() and publishes a dedicated informational-response diagnostic channel. AppSec subscribes to that channel and aborts the operation when the response is already blocked; otherwise, the original Node.js method runs unchanged.

This PR also includes test-infrastructure fixes needed for these tests to fail correctly if necessary:

  • Route synchronous Mocha hook errors through the runnable callback under allowUncaught, preserving timeout cleanup and normalizing falsy thrown values.
  • Update the IAST source-map TypeScript fixture for TypeScript 6 resolution behavior.

Motivation

Once AppSec has produced a blocking response, later calls to Node.js informational-response APIs must not write additional status lines to the socket. These methods were not covered by the existing response-operation guard, so application code could still call them after a request had been blocked.

When allowUncaught enabled, synchronous hook failures could escape through Mocha's uncaught-exception path, terminate a fixture before its reporter output was complete, and make later AppSec tests appear skipped or successful. Routing those failures through Mocha's runnable callback makes the suite report the original failure deterministically.

Additional Notes

  • AppSec tests cover channel subscription lifecycle and both blocked and non-blocked informational-response operations.
  • Mocha-hook tests cover asynchronous hook ordering, teardown suppression, callback timeout cleanup, and falsy thrown values under --allow-uncaught.
  • This is a semver-patch production fix.

The repo's .mocharc.js enables `allowUncaught`. When a before/after hook
throws synchronously, mocha's Runnable.run re-throws the error instead of
invoking the hook callback. Our Hook.prototype.run wrapper caught that
throw and re-threw it, relying on mocha's uncaughtException handler to
record the failure. That path is fragile: when a preceding hook is async,
the throw escapes in a promise-continuation context, the fixture process
dies before the JSON reporter emits anything, and the failure is silently
lost — the run appears to skip/pass instead of failing.

Route the caught error through the hook callback (`fn(err)`) instead, which
is the same path mocha uses without allowUncaught. This triggers
`self.fail(hook, err)` deterministically regardless of async ordering,
while preserving suppression of teardown errors when an earlier runnable
already failed.

Add coverage for both the async-before-all ordering and after-all
suppression under `--allow-uncaught`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@dd-octo-sts

dd-octo-sts Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.71 MB
Deduped: 7.37 MB
No deduping: 7.37 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.1 | 122.62 kB | 438.86 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 96.57% (+0.03%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 429732a | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Jul 10, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-13 18:44:26

Comparing candidate commit 429732a in PR branch pabloerhard/fix-test-swallowing with baseline commit f542182 in branch master.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 2313 metrics, 45 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:appsec-appsec-enabled-24

  • unstable execution_time [-211.561ms; +216.184ms] or [-7.966%; +8.140%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-235.031ms; +225.205ms] or [-9.265%; +8.877%]

scenario:appsec-appsec-enabled-with-attacks-24

  • unstable execution_time [-161.700ms; +147.921ms] or [-5.243%; +4.796%]

scenario:appsec-appsec-enabled-with-attacks-26

  • unstable execution_time [-184245.519µs; +185908.519µs] or [-6.363%; +6.420%]

scenario:appsec-control-20

  • unstable execution_time [-109.739ms; +131.270ms] or [-6.716%; +8.034%]

scenario:appsec-control-24

  • unstable execution_time [-116015.330µs; +117236.097µs] or [-9.345%; +9.443%]

scenario:appsec-control-26

  • unstable execution_time [-126.050ms; +130.350ms] or [-10.188%; +10.535%]

scenario:appsec-iast-no-vulnerability-iast-enabled-always-active-20

  • unstable execution_time [-10.749ms; +22.572ms] or [-4.258%; +8.941%]

scenario:appsec-iast-no-vulnerability-iast-enabled-default-config-20

  • unstable execution_time [-13706.626µs; +12474.153µs] or [-5.464%; +4.972%]

scenario:child_process-shell-string-24

  • unstable cpu_usage_percentage [-7.157%; +4.349%]
  • unstable execution_time [-18.325ms; +28.960ms] or [-5.582%; +8.822%]
  • unstable throughput [-235824.195op/s; +155052.947op/s] or [-6.566%; +4.317%]

scenario:debugger-line-probe-with-snapshot-default-24

  • unstable cpu_user_time [-2443.045ms; +2721.814ms] or [-27.228%; +30.335%]
  • unstable execution_time [-2530.597ms; +2777.813ms] or [-26.146%; +28.701%]
  • unstable instructions [-20.6G instructions; +23.0G instructions] or [-28.016%; +31.313%]
  • unstable max_rss_usage [-10970.663KB; +11136.263KB] or [-6.881%; +6.985%]
  • unstable throughput [-733.060op/s; +674.553op/s] or [-21.283%; +19.584%]

scenario:debugger-line-probe-with-snapshot-minimal-24

  • unstable cpu_user_time [-1.827s; +4.011s] or [-20.463%; +44.925%]
  • unstable execution_time [-1.914s; +4.124s] or [-19.855%; +42.769%]
  • unstable instructions [-15.3G instructions; +33.8G instructions] or [-21.026%; +46.283%]
  • unstable max_rss_usage [-7.853MB; +16.548MB] or [-4.933%; +10.396%]
  • unstable throughput [-1108.300op/s; +514.248op/s] or [-31.984%; +14.841%]

scenario:debugger-line-probe-with-snapshot-minimal-26

  • unstable cpu_user_time [-3.179s; +0.430s] or [-31.358%; +4.244%]
  • unstable execution_time [-3.213s; +0.411s] or [-29.494%; +3.776%]
  • unstable instructions [-28.5G instructions; +3.9G instructions] or [-33.546%; +4.610%]
  • unstable throughput [-80.730op/s; +665.338op/s] or [-2.615%; +21.548%]

scenario:debugger-line-probe-without-snapshot-24

  • unstable cpu_user_time [-2522.194ms; +3560.886ms] or [-27.018%; +38.145%]
  • unstable execution_time [-2518.336ms; +3580.724ms] or [-25.071%; +35.647%]
  • unstable instructions [-21.7G instructions; +30.5G instructions] or [-28.245%; +39.714%]
  • unstable max_rss_usage [-9.948MB; +15.029MB] or [-6.182%; +9.339%]
  • unstable throughput [-976.612op/s; +704.664op/s] or [-29.116%; +21.008%]

scenario:debugger-line-probe-without-snapshot-26

  • unstable cpu_user_time [-2847.614ms; +2871.435ms] or [-28.583%; +28.822%]
  • unstable execution_time [-2859.024ms; +2867.803ms] or [-26.714%; +26.796%]
  • unstable instructions [-25677.8M instructions; +25763.8M instructions] or [-30.698%; +30.801%]
  • unstable max_rss_usage [-9354.763KB; +9646.763KB] or [-5.815%; +5.997%]
  • unstable throughput [-628.422op/s; +624.334op/s] or [-20.155%; +20.024%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-497.565ms; +187.541ms] or [-10.059%; +3.791%]
  • unstable execution_time [-498.286ms; +186.563ms] or [-9.922%; +3.715%]
  • unstable throughput [-62717.301op/s; +172472.670op/s] or [-3.755%; +10.326%]

scenario:plugin-claude-agent-sdk-compact-stream-scan-26

  • unstable cpu_usage_percentage [-6.257%; +4.171%]

scenario:plugin-graphql-long-with-depth-on-max-20

  • unstable cpu_user_time [-723.714ms; +747.072ms] or [-5.627%; +5.809%]
  • unstable execution_time [-733.218ms; +748.748ms] or [-5.577%; +5.695%]
  • unstable throughput [-3.417op/s; +3.341op/s] or [-5.579%; +5.455%]

scenario:plugin-mongodb-core-plain-find-26

  • unstable execution_time [-86.881ms; +152.363ms] or [-4.147%; +7.273%]

scenario:test-optimization-large-suite-20

  • unstable max_rss_usage [-5.434MB; +3.396MB] or [-6.760%; +4.225%]

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.60%. Comparing base (f542182) to head (429732a).
⚠️ Report is 8 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9290      +/-   ##
==========================================
+ Coverage   96.57%   96.60%   +0.03%     
==========================================
  Files         918      919       +1     
  Lines      121564   121691     +127     
  Branches    20380    20759     +379     
==========================================
+ Hits       117399   117563     +164     
+ Misses       4165     4128      -37     
Flag Coverage Δ
aiguard 53.56% <ø> (-0.11%) ⬇️
aiguard-integration 57.01% <53.57%> (+<0.01%) ⬆️
apm-bucket-0 53.79% <ø> (-0.05%) ⬇️
apm-bucket-1 58.07% <53.57%> (-0.05%) ⬇️
apm-bucket-2 56.11% <53.57%> (-0.05%) ⬇️
apm-capabilities-tracing 60.34% <47.05%> (+0.02%) ⬆️
apm-integrations-aerospike 52.94% <ø> (-0.05%) ⬇️
apm-integrations-confluentinc-kafka-javascript 57.06% <ø> (-0.05%) ⬇️
apm-integrations-couchbase 53.27% <ø> (-0.05%) ⬇️
apm-integrations-http 57.96% <55.88%> (-0.04%) ⬇️
apm-integrations-kafkajs 57.71% <ø> (-0.06%) ⬇️
apm-integrations-next 54.24% <53.57%> (-0.04%) ⬇️
apm-integrations-prisma 54.17% <53.57%> (-0.04%) ⬇️
apm-integrations-tedious 53.04% <53.57%> (-0.04%) ⬇️
appsec 69.00% <61.76%> (-0.06%) ⬇️
appsec-express_fastify_graphql 65.59% <61.76%> (-0.06%) ⬇️
appsec-integration 51.98% <94.11%> (+6.39%) ⬆️
appsec-kafka_ldapjs_lodash 59.09% <53.57%> (-0.05%) ⬇️
appsec-mongodb-core_mongoose_mysql 62.25% <61.76%> (-0.03%) ⬇️
appsec-next 52.85% <55.88%> (-0.04%) ⬇️
appsec-node-serialize_passport_postgres 61.88% <61.76%> (-0.04%) ⬇️
appsec-sourcing_stripe_template 60.34% <61.76%> (+0.07%) ⬆️
debugger 65.72% <53.57%> (-0.01%) ⬇️
instrumentations-bucket-0 48.75% <ø> (-0.04%) ⬇️
instrumentations-bucket-1 54.96% <53.57%> (-0.04%) ⬇️
instrumentations-bucket-10 56.62% <55.88%> (-0.04%) ⬇️
instrumentations-bucket-11 48.74% <ø> (-0.05%) ⬇️
instrumentations-bucket-12 48.85% <53.57%> (-0.04%) ⬇️
instrumentations-bucket-13 48.68% <ø> (-0.05%) ⬇️
instrumentations-bucket-2 49.75% <53.57%> (-0.03%) ⬇️
instrumentations-bucket-3 53.83% <53.57%> (-0.04%) ⬇️
instrumentations-bucket-4 49.16% <ø> (-0.05%) ⬇️
instrumentations-bucket-5 53.01% <53.57%> (-0.03%) ⬇️
instrumentations-bucket-6 55.60% <53.57%> (-0.05%) ⬇️
instrumentations-bucket-7 53.61% <53.57%> (-0.04%) ⬇️
instrumentations-bucket-8 54.64% <53.57%> (-0.04%) ⬇️
instrumentations-bucket-9 56.10% <55.88%> (-0.03%) ⬇️
instrumentations-instrumentation-couchbase 48.18% <ø> (-0.05%) ⬇️
instrumentations-integration-esbuild 33.98% <53.57%> (+0.01%) ⬆️
llmobs-ai_anthropic_bedrock 57.73% <53.57%> (-0.04%) ⬇️
llmobs-bucket-1 56.79% <53.57%> (-0.23%) ⬇️
llmobs-openai 57.56% <53.57%> (-0.04%) ⬇️
llmobs-sdk 59.95% <ø> (-0.04%) ⬇️
llmobs-vertex-ai 54.21% <53.57%> (-0.04%) ⬇️
master-coverage 96.60% <100.00%> (?)
openfeature 54.62% <53.57%> (+0.01%) ⬆️
openfeature-unit 49.83% <ø> (-0.05%) ⬇️
platform-core_esbuild_instrumentations-misc 38.47% <53.57%> (-0.01%) ⬇️
platform-integration 62.23% <53.57%> (+<0.01%) ⬆️
platform-shimmer_unit-guardrails_webpack 37.29% <53.57%> (-0.02%) ⬇️
plugins-bucket-0 53.18% <53.57%> (-0.04%) ⬇️
plugins-bucket-1 55.09% <53.57%> (+0.01%) ⬆️
plugins-bucket-11 55.60% <53.57%> (-0.04%) ⬇️
plugins-bucket-18 57.07% <53.57%> (-0.04%) ⬇️
plugins-bucket-19 55.35% <53.57%> (-0.05%) ⬇️
plugins-bucket-20 57.44% <53.57%> (-0.05%) ⬇️
plugins-bucket-4 53.85% <53.57%> (-0.04%) ⬇️
plugins-bullmq_cassandra_cookie 57.36% <10.71%> (-0.08%) ⬇️
plugins-cookie-parser_crypto_dd-trace-api 52.32% <ø> (-0.05%) ⬇️
plugins-fetch_fs_generic-pool 54.46% <53.57%> (-0.04%) ⬇️
plugins-google-cloud-pubsub_grpc_handlebars 59.86% <53.57%> (-0.05%) ⬇️
plugins-hapi_hono_ioredis 55.86% <53.57%> (-0.05%) ⬇️
plugins-jest_knex_langgraph 51.67% <ø> (-0.04%) ⬇️
plugins-ldapjs_light-my-request_limitd-client 53.42% <53.57%> (-0.06%) ⬇️
plugins-lodash_mariadb_memcached 54.21% <ø> (-0.05%) ⬇️
plugins-moleculer_mongodb_mongodb-core 57.28% <53.57%> (-0.05%) ⬇️
plugins-mongoose_multer_mysql 54.71% <53.57%> (-0.04%) ⬇️
plugins-mysql2_nats_node-serialize 56.21% <ø> (-0.04%) ⬇️
plugins-opensearch_passport-http_pino 55.05% <53.57%> (-0.05%) ⬇️
plugins-postgres_process_pug 54.29% <ø> (-0.05%) ⬇️
plugins-redis_router_sequelize 57.03% <53.57%> (-0.05%) ⬇️
plugins-test-and-upstream-rhea_undici_url 57.03% <53.57%> (-0.05%) ⬇️
plugins-valkey_vm_winston 53.93% <53.57%> (+0.04%) ⬆️
plugins-ws 54.80% <53.57%> (-0.05%) ⬇️
profiling 58.20% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-aws-sdk 50.67% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-bedrockruntime 50.69% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-client 51.97% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-dynamodb 51.75% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-eventbridge 46.26% <53.57%> (-0.03%) ⬇️
serverless-aws-sdk-kinesis 54.71% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-lambda 52.79% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-s3 51.54% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-serverless-peer-service 54.73% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-sns 55.48% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-sqs 55.99% <53.57%> (+0.03%) ⬆️
serverless-aws-sdk-stepfunctions 51.25% <53.57%> (-0.04%) ⬇️
serverless-aws-sdk-util 48.48% <ø> (-0.05%) ⬇️
serverless-bucket-0 55.23% <53.57%> (+0.01%) ⬆️
serverless-bucket-1 56.00% <53.57%> (-0.04%) ⬇️
test-optimization-cucumber 72.98% <53.57%> (+0.02%) ⬆️
test-optimization-cypress 66.38% <53.57%> (+0.07%) ⬆️
test-optimization-jest 74.25% <53.57%> (+0.31%) ⬆️
test-optimization-mocha 74.70% <53.57%> (+0.44%) ⬆️
test-optimization-playwright-playwright-atr 61.57% <53.57%> (-0.01%) ⬇️
test-optimization-playwright-playwright-efd 61.76% <53.57%> (+<0.01%) ⬆️
test-optimization-playwright-playwright-final-status 61.71% <53.57%> (-0.01%) ⬇️
test-optimization-playwright-playwright-impacted-tests 61.44% <53.57%> (+0.16%) ⬆️
test-optimization-playwright-playwright-reporting 61.34% <53.57%> (-0.01%) ⬇️
test-optimization-playwright-playwright-test-management 62.25% <53.57%> (-0.12%) ⬇️
test-optimization-playwright-playwright-test-span 61.48% <53.57%> (-0.06%) ⬇️
test-optimization-selenium 60.66% <53.57%> (-0.17%) ⬇️
test-optimization-testopt 59.15% <53.57%> (+0.08%) ⬆️
test-optimization-vitest 71.58% <53.57%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

pabloerhard and others added 2 commits July 10, 2026 16:25
The IAST sourcemaps integration test's `before` hook compiles a TS fixture
with `npx tsc`. Under TypeScript 6.x this failed for two reasons, so the
hook threw:

- TS5107: `moduleResolution: "node"` (node10) is now a hard deprecation
  error. Silenced with `"ignoreDeprecations": "6.0"` (keeps emit identical).
- TS2591: `process`/`crypto` globals unresolved. TS 6.x no longer
  auto-includes `@types` from grandparent `node_modules`, and the sandbox
  installs deps at its root while tsc runs two levels down. Adding
  `"types": ["node"]` resolves `@types/node` via normal module walk-up.

This hook failure was previously swallowed under mocha's allowUncaught,
which also killed the mocha process and silently skipped every appsec
integration spec loaded after it (RASP, multer, standalone-asm, etc.).
The companion mocha-hooks fix surfaces the hook error instead; this commit
makes the compile actually succeed so the whole appsec suite runs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@pabloerhard
pabloerhard marked this pull request as ready for review July 13, 2026 14:36
@pabloerhard
pabloerhard requested review from a team as code owners July 13, 2026 14:36
@pabloerhard
pabloerhard requested review from crysmags and removed request for a team July 13, 2026 14:36

@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: 05b6ea2e88

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/dd-trace/test/setup/mocha-hooks.js Outdated

@CarlesDD CarlesDD 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.

LGTM from AppSec. Fix is correct, no unintended header logic gets triggered. Left one non-blocking naming suggestion inline.

Comment on lines +224 to +240
function wrapInformationalResponse (originalMethod) {
return function wrappedInformationalResponse (...args) {
if (!startSetHeaderCh.hasSubscribers) {
return Reflect.apply(originalMethod, this, args)
}

const abortController = new AbortController()
startSetHeaderCh.publish({ res: this, abortController })

if (abortController.signal.aborted) {
return
}

return Reflect.apply(originalMethod, this, args)
}
}

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.

Reusing set-header:start channel for informational responses (1xx) is misleading, they're not header mutations. Consider a dedicated channel (datadog:http:server:informational-response:start for example) with its own subscribe in appsec/index.js as set-header channel already has.

@BridgeAR BridgeAR left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems to not mainly be about our test setup anymore but more about the AppSec fix. Ideally, the appsec one would land before the test fix. But I think it is fine as long as we declare it as AppSec fix in one go

} catch (err) {
if (shouldSuppress(this)) return fn()
throw err
return this.callback(shouldSuppress(this) ? undefined : err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return this.callback(shouldSuppress(this) ? undefined : err)
return this.callback(shouldSuppress(this) ? undefined : Runnable.toValueOrError(err))

Runnable must be imported from mocha above. With this change, we will also handle falsy values correct, even undefined :)

@pabloerhard pabloerhard changed the title test(mocha-hooks): stop swallowing hook errors under allowUncaught fix(appsec): suppress informational responses after blocking requests Jul 13, 2026
@BridgeAR

Copy link
Copy Markdown
Member

Please make sure to write a proper description when landing :)

@pabloerhard
pabloerhard merged commit 0b8ae4b into master Jul 13, 2026
694 of 695 checks passed
@pabloerhard
pabloerhard deleted the pabloerhard/fix-test-swallowing branch July 13, 2026 19:58
dd-octo-sts Bot pushed a commit that referenced this pull request Jul 14, 2026
…#9290)

* test(mocha-hooks): stop swallowing hook errors under allowUncaught

The repo's .mocharc.js enables `allowUncaught`. When a before/after hook
throws synchronously, mocha's Runnable.run re-throws the error instead of
invoking the hook callback. Our Hook.prototype.run wrapper caught that
throw and re-threw it, relying on mocha's uncaughtException handler to
record the failure. That path is fragile: when a preceding hook is async,
the throw escapes in a promise-continuation context, the fixture process
dies before the JSON reporter emits anything, and the failure is silently
lost — the run appears to skip/pass instead of failing.

Route the caught error through the hook callback (`fn(err)`) instead, which
is the same path mocha uses without allowUncaught. This triggers
`self.fail(hook, err)` deterministically regardless of async ordering,
while preserving suppression of teardown errors when an earlier runnable
already failed.

Add coverage for both the async-before-all ordering and after-all
suppression under `--allow-uncaught`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* test(iast): fix tsc build in IAST sourcemaps integration test

The IAST sourcemaps integration test's `before` hook compiles a TS fixture
with `npx tsc`. Under TypeScript 6.x this failed for two reasons, so the
hook threw:

- TS5107: `moduleResolution: "node"` (node10) is now a hard deprecation
  error. Silenced with `"ignoreDeprecations": "6.0"` (keeps emit identical).
- TS2591: `process`/`crypto` globals unresolved. TS 6.x no longer
  auto-includes `@types` from grandparent `node_modules`, and the sandbox
  installs deps at its root while tsc runs two levels down. Adding
  `"types": ["node"]` resolves `@types/node` via normal module walk-up.

This hook failure was previously swallowed under mocha's allowUncaught,
which also killed the mocha process and silently skipped every appsec
integration spec loaded after it (RASP, multer, standalone-asm, etc.).
The companion mocha-hooks fix surfaces the hook error instead; this commit
makes the compile actually succeed so the whole appsec suite runs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix http tests in node 26

* clear timeout with callbacks

* rename dc channel

* handle falsy values

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
@dd-octo-sts dd-octo-sts Bot mentioned this pull request Jul 14, 2026
dd-octo-sts Bot pushed a commit that referenced this pull request Jul 14, 2026
…#9290)

* test(mocha-hooks): stop swallowing hook errors under allowUncaught

The repo's .mocharc.js enables `allowUncaught`. When a before/after hook
throws synchronously, mocha's Runnable.run re-throws the error instead of
invoking the hook callback. Our Hook.prototype.run wrapper caught that
throw and re-threw it, relying on mocha's uncaughtException handler to
record the failure. That path is fragile: when a preceding hook is async,
the throw escapes in a promise-continuation context, the fixture process
dies before the JSON reporter emits anything, and the failure is silently
lost — the run appears to skip/pass instead of failing.

Route the caught error through the hook callback (`fn(err)`) instead, which
is the same path mocha uses without allowUncaught. This triggers
`self.fail(hook, err)` deterministically regardless of async ordering,
while preserving suppression of teardown errors when an earlier runnable
already failed.

Add coverage for both the async-before-all ordering and after-all
suppression under `--allow-uncaught`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* test(iast): fix tsc build in IAST sourcemaps integration test

The IAST sourcemaps integration test's `before` hook compiles a TS fixture
with `npx tsc`. Under TypeScript 6.x this failed for two reasons, so the
hook threw:

- TS5107: `moduleResolution: "node"` (node10) is now a hard deprecation
  error. Silenced with `"ignoreDeprecations": "6.0"` (keeps emit identical).
- TS2591: `process`/`crypto` globals unresolved. TS 6.x no longer
  auto-includes `@types` from grandparent `node_modules`, and the sandbox
  installs deps at its root while tsc runs two levels down. Adding
  `"types": ["node"]` resolves `@types/node` via normal module walk-up.

This hook failure was previously swallowed under mocha's allowUncaught,
which also killed the mocha process and silently skipped every appsec
integration spec loaded after it (RASP, multer, standalone-asm, etc.).
The companion mocha-hooks fix surfaces the hook error instead; this commit
makes the compile actually succeed so the whole appsec suite runs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix http tests in node 26

* clear timeout with callbacks

* rename dc channel

* handle falsy values

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
@dd-octo-sts dd-octo-sts Bot mentioned this pull request Jul 14, 2026
This was referenced Jul 14, 2026
juan-fernandez pushed a commit that referenced this pull request Jul 14, 2026
…#9290)

* test(mocha-hooks): stop swallowing hook errors under allowUncaught

The repo's .mocharc.js enables `allowUncaught`. When a before/after hook
throws synchronously, mocha's Runnable.run re-throws the error instead of
invoking the hook callback. Our Hook.prototype.run wrapper caught that
throw and re-threw it, relying on mocha's uncaughtException handler to
record the failure. That path is fragile: when a preceding hook is async,
the throw escapes in a promise-continuation context, the fixture process
dies before the JSON reporter emits anything, and the failure is silently
lost — the run appears to skip/pass instead of failing.

Route the caught error through the hook callback (`fn(err)`) instead, which
is the same path mocha uses without allowUncaught. This triggers
`self.fail(hook, err)` deterministically regardless of async ordering,
while preserving suppression of teardown errors when an earlier runnable
already failed.

Add coverage for both the async-before-all ordering and after-all
suppression under `--allow-uncaught`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* test(iast): fix tsc build in IAST sourcemaps integration test

The IAST sourcemaps integration test's `before` hook compiles a TS fixture
with `npx tsc`. Under TypeScript 6.x this failed for two reasons, so the
hook threw:

- TS5107: `moduleResolution: "node"` (node10) is now a hard deprecation
  error. Silenced with `"ignoreDeprecations": "6.0"` (keeps emit identical).
- TS2591: `process`/`crypto` globals unresolved. TS 6.x no longer
  auto-includes `@types` from grandparent `node_modules`, and the sandbox
  installs deps at its root while tsc runs two levels down. Adding
  `"types": ["node"]` resolves `@types/node` via normal module walk-up.

This hook failure was previously swallowed under mocha's allowUncaught,
which also killed the mocha process and silently skipped every appsec
integration spec loaded after it (RASP, multer, standalone-asm, etc.).
The companion mocha-hooks fix surfaces the hook error instead; this commit
makes the compile actually succeed so the whole appsec suite runs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix http tests in node 26

* clear timeout with callbacks

* rename dc channel

* handle falsy values

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
juan-fernandez pushed a commit that referenced this pull request Jul 14, 2026
…#9290)

* test(mocha-hooks): stop swallowing hook errors under allowUncaught

The repo's .mocharc.js enables `allowUncaught`. When a before/after hook
throws synchronously, mocha's Runnable.run re-throws the error instead of
invoking the hook callback. Our Hook.prototype.run wrapper caught that
throw and re-threw it, relying on mocha's uncaughtException handler to
record the failure. That path is fragile: when a preceding hook is async,
the throw escapes in a promise-continuation context, the fixture process
dies before the JSON reporter emits anything, and the failure is silently
lost — the run appears to skip/pass instead of failing.

Route the caught error through the hook callback (`fn(err)`) instead, which
is the same path mocha uses without allowUncaught. This triggers
`self.fail(hook, err)` deterministically regardless of async ordering,
while preserving suppression of teardown errors when an earlier runnable
already failed.

Add coverage for both the async-before-all ordering and after-all
suppression under `--allow-uncaught`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* test(iast): fix tsc build in IAST sourcemaps integration test

The IAST sourcemaps integration test's `before` hook compiles a TS fixture
with `npx tsc`. Under TypeScript 6.x this failed for two reasons, so the
hook threw:

- TS5107: `moduleResolution: "node"` (node10) is now a hard deprecation
  error. Silenced with `"ignoreDeprecations": "6.0"` (keeps emit identical).
- TS2591: `process`/`crypto` globals unresolved. TS 6.x no longer
  auto-includes `@types` from grandparent `node_modules`, and the sandbox
  installs deps at its root while tsc runs two levels down. Adding
  `"types": ["node"]` resolves `@types/node` via normal module walk-up.

This hook failure was previously swallowed under mocha's allowUncaught,
which also killed the mocha process and silently skipped every appsec
integration spec loaded after it (RASP, multer, standalone-asm, etc.).
The companion mocha-hooks fix surfaces the hook error instead; this commit
makes the compile actually succeed so the whole appsec suite runs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* fix http tests in node 26

* clear timeout with callbacks

* rename dc channel

* handle falsy values

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants