Skip to content

fix(cypress): failure-media metadata via query params + agent (evp_proxy) upload#9186

Merged
xinyeji merged 3 commits into
xinye.ji/cypress-failure-media-v2from
xinye.ji/cypress-failure-media-evp-proxy
Jul 2, 2026
Merged

fix(cypress): failure-media metadata via query params + agent (evp_proxy) upload#9186
xinyeji merged 3 commits into
xinye.ji/cypress-failure-media-v2from
xinye.ji/cypress-failure-media-evp-proxy

Conversation

@xinyeji

@xinyeji xinyeji commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Two coupled changes to the Cypress failure-media upload, both required to make agent-mode uploads work:

  1. Metadata moves from X-Dd-* headers to query params. The uploader now appends ?idempotency_key=<k>&captured_at_ms=<ms> (built with URLSearchParams) to the media path in both agentless and agent modes, and no longer sets X-Dd-Idempotency-Key / X-Dd-Media-Captured-At.
  2. Agent (evp_proxy) upload is enabled. Previously the agent-proxy exporter forced _testScreenshotUploadUrl = undefined, so canUploadTestScreenshots() always returned false in agent mode. It now points at the agent URL (in the evp-compatible branch), and the uploader builds the evp_proxy path + X-Datadog-EVP-Subdomain: api and drops the client DD-API-KEY (the Agent injects it).

Motivation

The Datadog Agent's evp_proxy forwards only an allow-listed set of headers and strips X-Dd-Idempotency-Key / X-Dd-Media-Captured-At. Agent-mode uploads therefore reached the backend with an empty idempotency key, which the media service rejected as MALFORMED. Query params pass through the proxy untouched.

This pairs with a dd-source backend change that now reads idempotency_key and captured_at_ms from the query string.

Because the values are URL-encoded via URLSearchParams, the header-safety hex hack (toIdempotencyHeaderValue) is no longer needed and has been removed — a non-ASCII filename in the idempotency key can no longer throw ERR_INVALID_CHAR.

End state

  • AgentlessPOST https://api.<site>/api/v2/ci/test-runs/<trace>/media?idempotency_key=...&captured_at_ms=... with DD-API-KEY, no EVP subdomain header.
  • AgentPOST <agent>/evp_proxy/v{N}/api/v2/ci/test-runs/<trace>/media?idempotency_key=...&captured_at_ms=... with X-Datadog-EVP-Subdomain: api and no client DD-API-KEY.

Stacked on

Base branch is xinye.ji/cypress-failure-media-v2.

Testing

  • eslint clean on all four changed files.
  • upload-test-screenshot.spec.js rewritten to assert query params (both modes) + the evp-proxy path/header/key behaviour — 5 passing.
  • ci-visibility-exporter.spec.js + agent-proxy.spec.js — 60 passing.

🤖 Generated with Claude Code

…ent (evp_proxy) upload

The Agent's evp_proxy strips X-Dd-* headers, so agent-mode failure-media uploads
reached the backend with an empty idempotency key. Move idempotency_key and
captured_at_ms to query params (survive the proxy) and enable the agent-mode upload
path via evp_proxy (X-Datadog-EVP-Subdomain: api). Pairs with the dd-source backend
change reading these from the query string.

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

dd-octo-sts Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.44 MB
Deduped: 7.51 MB
No deduping: 7.51 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.2.0 | 104.26 kB | 843.44 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

@xinyeji

xinyeji commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Paired backend change: ddoghq/dd-source#9350 — reads idempotency_key + captured_at_ms from the query string (matches what this PR sends).

@datadog-prod-us1-3

datadog-prod-us1-3 Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 90.00%
Overall Coverage: 65.31% (-22.65%)

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

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.69%. Comparing base (c3efe21) to head (cf0808f).
⚠️ Report is 1 commits behind head on xinye.ji/cypress-failure-media-v2.

Additional details and impacted files
@@                        Coverage Diff                         @@
##           xinye.ji/cypress-failure-media-v2    #9186   +/-   ##
==================================================================
  Coverage                              93.69%   93.69%           
==================================================================
  Files                                    893      893           
  Lines                                  51427    51432    +5     
  Branches                               11973    11976    +3     
==================================================================
+ Hits                                   48182    48187    +5     
  Misses                                  3245     3245           
Flag Coverage Δ
aiguard 34.87% <ø> (-0.01%) ⬇️
aiguard-integration 41.78% <ø> (-0.02%) ⬇️
apm-bucket-0 34.83% <ø> (-0.01%) ⬇️
apm-bucket-1 40.33% <ø> (-0.01%) ⬇️
apm-bucket-2 37.33% <ø> (-0.01%) ⬇️
apm-capabilities-tracing 48.71% <100.00%> (+<0.01%) ⬆️
apm-integrations-aerospike 33.12% <ø> (-0.01%) ⬇️
apm-integrations-confluentinc-kafka-javascript 40.02% <ø> (-0.01%) ⬇️
apm-integrations-couchbase 33.40% <ø> (-0.01%) ⬇️
apm-integrations-http 41.96% <ø> (+0.01%) ⬆️
apm-integrations-kafkajs 40.26% <ø> (+<0.01%) ⬆️
apm-integrations-next 29.50% <ø> (+0.03%) ⬆️
apm-integrations-prisma 35.03% <ø> (-0.01%) ⬇️
apm-integrations-tedious 33.89% <ø> (-0.01%) ⬇️
appsec 57.62% <ø> (-0.08%) ⬇️
appsec-express_fastify_graphql 53.67% <ø> (+<0.01%) ⬆️
appsec-integration 36.20% <ø> (-0.01%) ⬇️
appsec-kafka_ldapjs_lodash 43.58% <ø> (-0.08%) ⬇️
appsec-mongodb-core_mongoose_mysql 48.74% <ø> (-0.01%) ⬇️
appsec-next 28.01% <ø> (+<0.01%) ⬆️
appsec-node-serialize_passport_postgres 47.91% <ø> (-0.01%) ⬇️
appsec-sourcing_stripe_template 45.47% <ø> (-0.01%) ⬇️
debugger 44.40% <ø> (-0.02%) ⬇️
instrumentations-bucket-0 28.15% <ø> (-0.01%) ⬇️
instrumentations-bucket-1 37.40% <ø> (-0.01%) ⬇️
instrumentations-bucket-10 40.35% <ø> (-0.01%) ⬇️
instrumentations-bucket-11 27.95% <ø> (-0.01%) ⬇️
instrumentations-bucket-12 28.66% <ø> (-0.01%) ⬇️
instrumentations-bucket-13 27.78% <ø> (-0.01%) ⬇️
instrumentations-bucket-2 30.23% <ø> (-0.01%) ⬇️
instrumentations-bucket-3 35.90% <ø> (-0.01%) ⬇️
instrumentations-bucket-4 28.06% <ø> (-0.50%) ⬇️
instrumentations-bucket-5 36.27% <ø> (-0.01%) ⬇️
instrumentations-bucket-6 38.25% <ø> (-0.01%) ⬇️
instrumentations-bucket-7 36.01% <ø> (-0.01%) ⬇️
instrumentations-bucket-8 36.95% <ø> (-0.01%) ⬇️
instrumentations-bucket-9 39.45% <ø> (-0.01%) ⬇️
instrumentations-instrumentation-couchbase 46.54% <ø> (+0.06%) ⬆️
instrumentations-integration-esbuild 24.85% <ø> (-0.01%) ⬇️
llmobs-ai_anthropic_bedrock 39.53% <ø> (-0.01%) ⬇️
llmobs-google-genai_langchain_vertex-ai 36.97% <ø> (-0.01%) ⬇️
llmobs-openai 39.57% <ø> (-0.01%) ⬇️
llmobs-sdk 43.59% <ø> (-0.01%) ⬇️
master-coverage ?
openfeature 37.75% <ø> (-0.01%) ⬇️
openfeature-unit 50.39% <ø> (ø)
platform-core_esbuild_instrumentations-misc 23.35% <ø> (-0.01%) ⬇️
platform-integration 47.42% <ø> (-0.01%) ⬇️
platform-shimmer_unit-guardrails_webpack 18.88% <ø> (-0.02%) ⬇️
plugins-bucket-0 36.33% <ø> (-0.01%) ⬇️
plugins-bucket-1 39.59% <ø> (-0.01%) ⬇️
plugins-bucket-11 38.46% <ø> (-0.01%) ⬇️
plugins-bucket-17 39.15% <ø> (-0.01%) ⬇️
plugins-bucket-18 42.01% <ø> (-0.01%) ⬇️
plugins-bucket-19 39.56% <ø> (-0.01%) ⬇️
plugins-bucket-20 43.25% <ø> (-0.01%) ⬇️
plugins-bucket-4 37.71% <ø> (-0.01%) ⬇️
plugins-bullmq_cassandra_cookie 39.76% <ø> (+<0.01%) ⬆️
plugins-cookie-parser_crypto_dd-trace-api 33.21% <ø> (-0.01%) ⬇️
plugins-fetch_fs_generic-pool 36.05% <ø> (+0.02%) ⬆️
plugins-google-cloud-pubsub_grpc_handlebars 43.10% <ø> (-0.01%) ⬇️
plugins-hapi_hono_ioredis 37.78% <ø> (-0.01%) ⬇️
plugins-jest_knex_langgraph 32.60% <ø> (-0.01%) ⬇️
plugins-ldapjs_light-my-request_limitd-client 27.84% <ø> (-0.01%) ⬇️
plugins-lodash_mariadb_memcached 35.17% <ø> (-0.01%) ⬇️
plugins-mongodb_mongodb-core_mongoose 36.30% <ø> (-0.01%) ⬇️
plugins-multer_mysql_mysql2 35.14% <ø> (-0.01%) ⬇️
plugins-nats_node-serialize_opensearch 37.14% <ø> (-0.01%) ⬇️
plugins-passport-http_pino_postgres 35.52% <ø> (-0.01%) ⬇️
plugins-process_pug_redis 34.26% <ø> (+<0.01%) ⬆️
plugins-undici_url_valkey 35.88% <ø> (-0.01%) ⬇️
plugins-vm_winston_ws 37.55% <ø> (-0.01%) ⬇️
profiling 43.61% <ø> (-0.02%) ⬇️
serverless-aws-sdk-aws-sdk 33.29% <ø> (-0.01%) ⬇️
serverless-aws-sdk-bedrockruntime 32.16% <ø> (-0.01%) ⬇️
serverless-aws-sdk-client 37.21% <ø> (+0.04%) ⬆️
serverless-aws-sdk-dynamodb 34.22% <ø> (+0.12%) ⬆️
serverless-aws-sdk-eventbridge 27.24% <ø> (-0.01%) ⬇️
serverless-aws-sdk-kinesis 37.40% <ø> (-0.01%) ⬇️
serverless-aws-sdk-lambda 34.59% <ø> (-0.01%) ⬇️
serverless-aws-sdk-s3 32.59% <ø> (-0.01%) ⬇️
serverless-aws-sdk-serverless-peer-service 39.47% <ø> (-0.01%) ⬇️
serverless-aws-sdk-sns 38.61% <ø> (+0.35%) ⬆️
serverless-aws-sdk-sqs 37.99% <ø> (-0.01%) ⬇️
serverless-aws-sdk-stepfunctions 33.18% <ø> (-0.01%) ⬇️
serverless-aws-sdk-util 47.95% <ø> (ø)
serverless-bucket-0 39.45% <ø> (-0.01%) ⬇️
serverless-lambda 34.33% <ø> (-0.01%) ⬇️
test-optimization-cucumber 52.17% <10.00%> (-0.13%) ⬇️
test-optimization-cypress 49.83% <80.00%> (-0.10%) ⬇️
test-optimization-jest 55.15% <10.00%> (-0.12%) ⬇️
test-optimization-mocha 53.25% <10.00%> (-0.02%) ⬇️
test-optimization-playwright-playwright-atr 43.22% <10.00%> (-0.02%) ⬇️
test-optimization-playwright-playwright-efd 43.50% <0.00%> (-0.02%) ⬇️
test-optimization-playwright-playwright-final-status 43.62% <0.00%> (-0.25%) ⬇️
test-optimization-playwright-playwright-impacted-tests 43.05% <0.00%> (-0.02%) ⬇️
test-optimization-playwright-playwright-reporting 43.16% <10.00%> (-0.02%) ⬇️
test-optimization-playwright-playwright-test-management 44.82% <0.00%> (+0.19%) ⬆️
test-optimization-playwright-playwright-test-span 44.36% <10.00%> (-0.08%) ⬇️
test-optimization-selenium 45.19% <10.00%> (-0.02%) ⬇️
test-optimization-testopt 47.95% <10.00%> (-0.03%) ⬇️
test-optimization-vitest 50.50% <10.00%> (-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.

…vp_proxy

The Agent's evp_proxy validates the forwarded query string against a restrictive
charset and rejects a raw Cypress screenshot filename (spaces, parens), so the
query-param upload 502'd in agent mode. Restore the reviewed encoding
(<traceId>:<hex(filename)>) applied to the query value: trace id stays readable,
filename is hex-safe. Verified 201 through evp_proxy end-to-end.

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

pr-commenter Bot commented Jul 2, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-02 14:22:14

Comparing candidate commit cf0808f in PR branch xinye.ji/cypress-failure-media-evp-proxy with baseline commit c3efe21 in branch xinye.ji/cypress-failure-media-v2.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 2252 metrics, 34 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-20

  • unstable execution_time [-187.889ms; +195.175ms] or [-5.053%; +5.249%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-206.880ms; +212.085ms] or [-8.271%; +8.479%]

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

  • unstable execution_time [-164.700ms; +150.070ms] or [-5.722%; +5.213%]

scenario:appsec-control-20

  • unstable execution_time [-138.347ms; +180.940ms] or [-7.985%; +10.444%]

scenario:appsec-control-24

  • unstable execution_time [-102.549ms; +99.130ms] or [-8.450%; +8.168%]

scenario:appsec-control-26

  • unstable execution_time [-115.396ms; +119.133ms] or [-9.558%; +9.868%]

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

  • unstable cpu_user_time [-1654.432ms; +555.865ms] or [-20.833%; +7.000%]
  • unstable execution_time [-1698.621ms; +574.439ms] or [-19.730%; +6.672%]
  • unstable instructions [-14.3G instructions; +4.6G instructions] or [-22.149%; +7.134%]
  • unstable throughput [-171.911op/s; +493.813op/s] or [-4.479%; +12.866%]

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

  • unstable cpu_user_time [-2159.150ms; +3325.545ms] or [-23.042%; +35.489%]
  • unstable execution_time [-2195.362ms; +3366.497ms] or [-21.842%; +33.493%]
  • unstable instructions [-19.1G instructions; +29.5G instructions] or [-24.548%; +37.860%]
  • unstable max_rss_usage [-5.982MB; +9.912MB] or [-3.769%; +6.245%]
  • unstable throughput [-730.998op/s; +491.863op/s] or [-22.357%; +15.043%]

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

  • unstable cpu_user_time [-1725.594ms; +571.888ms] or [-21.725%; +7.200%]
  • unstable execution_time [-1743.204ms; +583.988ms] or [-20.223%; +6.775%]
  • unstable instructions [-14.7G instructions; +4.8G instructions] or [-22.701%; +7.411%]
  • unstable throughput [-170.964op/s; +498.166op/s] or [-4.454%; +12.980%]

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

  • unstable cpu_user_time [-1895.528ms; +574.845ms] or [-20.268%; +6.147%]
  • unstable execution_time [-1889.433ms; +595.837ms] or [-18.819%; +5.935%]
  • unstable instructions [-16.6G instructions; +5.1G instructions] or [-21.315%; +6.513%]
  • unstable throughput [-128.941op/s; +416.700op/s] or [-3.939%; +12.729%]

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

  • unstable cpu_user_time [-1619.288ms; +543.248ms] or [-20.505%; +6.879%]
  • unstable execution_time [-1661.119ms; +567.032ms] or [-19.344%; +6.603%]
  • unstable instructions [-13.8G instructions; +4.5G instructions] or [-21.479%; +6.994%]
  • unstable throughput [-171.794op/s; +486.667op/s] or [-4.468%; +12.658%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-418.698ms; +265.446ms] or [-8.319%; +5.274%]
  • unstable execution_time [-416.061ms; +261.218ms] or [-8.144%; +5.113%]
  • unstable throughput [-89152.896op/s; +143056.736op/s] or [-5.432%; +8.716%]

scenario:log-with-debug-20

  • unstable max_rss_usage [-8.069MB; +5.281MB] or [-7.009%; +4.588%]

scenario:plugin-graphql-long-with-depth-and-collapse-off-20

  • unstable max_rss_usage [-38.346MB; +25.810MB] or [-10.040%; +6.757%]

scenario:plugin-graphql-long-with-depth-off-20

  • unstable max_rss_usage [-5942.171KB; +7527.886KB] or [-4.558%; +5.775%]

scenario:test-optimization-large-suite-20

  • unstable max_rss_usage [-4199.088KB; +6081.755KB] or [-5.233%; +7.579%]

… headers

The mock intake and the integration assertions still expected the old header-borne
metadata, so the cypress media tests failed after the query-param move. Align them:
the intake parses idempotency_key/captured_at_ms from the query, the path assertion
ignores the query string, and a guard confirms the X-Dd-* metadata headers are gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@xinyeji
xinyeji marked this pull request as ready for review July 2, 2026 14:25
@xinyeji
xinyeji requested a review from a team as a code owner July 2, 2026 14:25
@xinyeji
xinyeji merged commit 577dde6 into xinye.ji/cypress-failure-media-v2 Jul 2, 2026
648 checks passed
@xinyeji
xinyeji deleted the xinye.ji/cypress-failure-media-evp-proxy branch July 2, 2026 14:28

@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: cf0808f67a

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

this._codeCoverageReportUrl = this._url
// Screenshot media uploads go through the Agent's evp_proxy: the uploader prefixes the
// path with evpProxyPrefix and sets X-Datadog-EVP-Subdomain: api (see uploadTestScreenshot).
this._testScreenshotUploadUrl = this._url

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 Update screenshot URL when agent URL changes

When tracer.setUrl() is called after the agent exporter has initialized, _setUrl() moves the trace and coverage writers to the new agent URL, but the screenshot upload URL remains the old this._url captured here. In agent/EVP mode with DD_TEST_FAILURE_SCREENSHOTS_ENABLED, Cypress media uploads will keep POSTing to the stale agent while the rest of CI Visibility uses the updated URL, so screenshots can be lost for users/tests that reconfigure the agent URL. Mirror the agentless exporter by updating _testScreenshotUploadUrl from setUrl() as well.

Useful? React with 👍 / 👎.

@datadog-prod-us1-3 datadog-prod-us1-3 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.

Datadog Autotest: WARN

The metadata-to-query-params migration and EVP proxy path construction are correct for all production code paths. One asymmetry found: the function guards every other invalid input (missing traceId, DD_API_KEY, idempotencyKey, invalid capturedAtMs) but has no guard for isEvpProxy: true with a missing/undefined evpProxyPrefix, which silently templates "undefined/api/v2/..." into the request path instead of returning an error. The production call site in agent-proxy always sets both fields together, so real users are unaffected today — but the missing guard is inconsistent with the function's own pattern.

📊 Validated against 5 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit cf0808f · What is Autotest? · Any feedback? Reach out in #autotest

Comment on lines +130 to +137
if (isEvpProxy) {
// Agent mode: prefix the evp_proxy path, tell the proxy which subdomain to forward to, and
// drop the API key — the Agent injects it. The query params survive the proxy.
options.path = `${evpProxyPrefix}${basePath}?${query}`
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
} else {
options.headers['DD-API-KEY'] = DD_API_KEY
}

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 isEvpProxy:true + missing evpProxyPrefix silently constructs "undefined/..." path

Any caller that sets isEvpProxy:true without evpProxyPrefix (e.g. a future test or subclass) silently issues an HTTP request to a broken path; the upload fails with a confusing 404 or ECONNREFUSED rather than a clear configuration error.

Assertion details
  • Input: uploadTestScreenshot({ ..., isEvpProxy: true, evpProxyPrefix: undefined }, cb) — calling the function with EVP proxy enabled but no prefix supplied
  • Expected: callback called with a clear Error ("evpProxyPrefix is required"), request not sent
  • Actual: request is sent to path "undefined/api/v2/ci/test-runs/.../media?..." — the literal string "undefined" is used as the path prefix, silently misrouting to a non-existent endpoint

Was this helpful? React 👍 or 👎
🤖 Datadog Autotest · What is Autotest? · Any feedback? Reach out in #autotest

Suggested change
if (isEvpProxy) {
// Agent mode: prefix the evp_proxy path, tell the proxy which subdomain to forward to, and
// drop the API key — the Agent injects it. The query params survive the proxy.
options.path = `${evpProxyPrefix}${basePath}?${query}`
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
} else {
options.headers['DD-API-KEY'] = DD_API_KEY
}
if (isEvpProxy) {
if (!evpProxyPrefix) {
return callback(new Error('evpProxyPrefix is required for Agent evp_proxy upload'))
}
// Agent mode: prefix the evp_proxy path, tell the proxy which subdomain to forward to, and
// drop the API key — the Agent injects it. The query params survive the proxy.
options.path = `${evpProxyPrefix}${basePath}?${query}`
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
} else {
options.headers['DD-API-KEY'] = DD_API_KEY
}

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants