fix(test): align live domain suites with staging sender-identity parity - #923
Merged
Conversation
added 2 commits
August 20, 2026 21:54
…2e suites The TS and Python SDK live domain suites asserted that deleting a never-verified throwaway domain returns sending_teardown:"confirmed". That was only ever true on deployments with no sending-identity provider configured (the receipt's synchronous-confirmed arm). With a provider configured, BeginDomainTeardownReceiptTx always starts the receipt at "pending" and the response only upgrades to "confirmed" when the in-request best-effort deprovision proves provider absence. Staging now runs with sender_identity enabled for prod parity, and its provider IAM policy intentionally denies identity calls outside the staging namespace — so the deprovision probe for a throwaway .example.com domain fails AccessDenied (not NotFound), the receipt fail-closes to "pending", and both live gates go red against correct, documented server behavior. First seen on the v1.7.9 release pipeline (TS gate failed; the Python gate carries the same assertion one step later). Accept both contract-valid receipt states, with a comment explaining why "confirmed" cannot be forced from these suites.
…IAM fence Suite 22 minted throwaway domains as <slug>.<zone> (dl-*.trymnexa.com). Since staging gained sender_identity parity (e2a-ops #318), every registered domain touches SES: verify auto-enqueues identity provisioning and delete runs a best-effort deprovision. For an out-of-fence name both calls AccessDeny against the staging policy (identity/*.staging.trymnexa.com only), the delete's teardown receipt fail-closes at "pending", and the suite — correctly honoring the contract's 'keep DNS published unless confirmed' — leaves the fixture's DNS records in place and records a dns-cleanup-failed FAIL finding. First seen on the v1.7.9 release pipeline: fail 0 tests, one finding, gate red. Hoist suite 35's environment-aware fixtureDomainSuffix() (staging -> staging.<zone>, prod -> <zone>) into harness/fixtures.ts and use it for both of suite 22's fixture domains. Suite 35's comment claiming suite 22 'has nothing for the fence to deny' predated staging sender-identity parity and is corrected. In-fence, the delete-time deprovision proves absence (NotFound), the receipt confirms synchronously, and DNS cleanup proceeds — same as production.
jiashuoz
added a commit
that referenced
this pull request
Aug 24, 2026
@e2a/sdk 5.7.0 was cut on 2026-08-16 and has been four commits behind the repo ever since, including a SECURITY fix that has sat in an "## Unreleased" changelog section the whole time: #909 reject dot-segment path params that retarget requests #918 shared base-URL resolution (E2A_API_URL, WSListener parity) #923 live domain suite alignment #926 dependency bump The gap is my error in #932. I scoped the TypeScript SDK by diffing against v1.7.10 and concluded "devDependency bump only, no republish". The correct baseline is the last PUBLISHED tag, ts-sdk-v5.7.0, which predates v1.7.10 by four days. So the Python client shipped its dot-segment guard as 5.8.0 while the TypeScript client kept serving 5.7.0 without one — and @e2a/cli depends on @e2a/sdk, so every CLI install carried the unfixed URL builder underneath. Minor rather than patch, matching the Python client: the guard throws E2AValidationError on path parameter values that previously produced a real, misdirected request. The changelog also gains the two user-visible #918 changes it never documented — the E2A_API_URL rename with E2A_BASE_URL deprecated, and WSListener no longer ignoring the environment (it honoured only an explicit opts.baseUrl and otherwise went straight to the hosted service, so a self-hosted deployment's listener silently pointed at api.e2a.dev). Note this is NOT the fail-closed change #918 made elsewhere: the TypeScript client still falls back to https://api.e2a.dev by design. No CLI republish needed — cli 2.5.0 requires @e2a/sdk ^5.7.0, which 5.8.0 satisfies, so installs pick the fix up on resolution. Co-authored-by: Jace <jace@team.tokencanopy.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The v1.7.9 release pipeline (e2a-ops run 32447588478) went red on two gates — both stale test expectations unmasked by staging finally running
sender_identityfor real (e2a-ops #318, the 2026-08-18 incident prevention work). Server behavior is correct and documented in both cases; no server code changes here.e2e-domains.test.ts(and the identical Python assertion, which sits one step later and never ran) asserted domain-delete returnssending_teardown: "confirmed". That was only ever true with no provider configured:BeginDomainTeardownReceiptTxstarts every receipt atpendingwhen a provider is configured, and the in-request best-effort deprovision can only upgrade it toconfirmedby proving provider absence. Staging's IAM fence denies SES calls for out-of-namespace names, so a throwaway.example.comfixture can never confirm there.dl-*.<zone>fixtures outside the staging fence (identity/*.staging.trymnexa.com). Its delete receipt fail-closed topending, so the suite — correctly honoring "keep DNS published unless confirmed" — left the fixture's 2 DNS records in place and recordeddns-cleanup-failed. All 230+ tests passed; the one finding failed the run.What
pending|confirmed) with comments explaining whyconfirmedcannot be forced from those suites.fixtureDomainSuffix()(staging →staging.<zone>, prod →<zone>) intoharness/fixtures.ts; suite 22 now uses it for both fixture domains. In-fence, delete-time deprovision proves absence (NotFound) and the receipt confirms synchronously — same as production. Also corrects suite 35's now-stale comment claiming suite 22 "has nothing for the fence to deny."Notes
isProductionTargetkeeps prod fixtures at the bare zone, and prod's unfenced SES user confirms teardown as before.🤖 Generated with Claude Code