fix(renderer): keep the HTTP shell from resurrecting a refused wall - #497
Merged
Conversation
When the JS ladder fails, the HTTP body substitutes for it so the caller gets content instead of an error. That is right until the shell IS the wall the ladder just refused, at which point the substitution hands back the exact body every tier rejected, as a billed success. Observed on prod after the ladder-tail guard shipped, in the engine's own log: JS escalation failed for soft-block status; surfacing HTTP shell with warning: blocked by an anti-bot wall that none of the 3 renderer tier(s) attempted could clear status_code=403 Both fallback arms already refuse to substitute when the caller pinned a renderer or asked for a screenshot, because those are contracts a silent substitution would break. A wall belongs in the same set for the same reason: it is not a fallback, it is the failure repeated. A shell that is not a wall still substitutes exactly as before, so the recall the fallback exists to protect is untouched.
Owner
Author
Verified on prodEngine pin Regression check, same run
One loose endThe error the customer sees is generic: "The fetch did not complete. This can be the target or our egress." The engine says |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Third and final link in the chain #494 → #496 → this. Each fix was correct and each time prod showed the wall still coming back, because the next layer down handed it over again.
The evidence
#496 made the ladder tail refuse a wall. It works — the engine's own log on prod says so:
Read that line carefully: my guard fired, returned the error, and the caller then surfaced the HTTP shell anyway. The shell is the same wall, so the customer still got
success: trueand a credit.The fix
When the JS ladder fails, the HTTP body substitutes for it so the caller gets content instead of nothing. Both fallback arms already decline to substitute in two cases: the caller pinned a renderer, or asked for a screenshot — contracts a silent substitution would break.
A wall belongs in the same set, for the same reason: it is not a fallback, it is the failure repeated. Added to the existing guard expression at both sites rather than as a new branch.
A shell that is not a wall still substitutes exactly as before, so the recall this fallback exists to protect is untouched.
Verification
cargo test --workspace: 4227 passedcargo test -p crw-renderer --features camoufox,cloak,cdp: 1025 passedhttp_shell_fallback_does_not_resurrect_a_wall; disabling both guards makes it fail, so it pins the behaviour rather than passing incidentallyWhy this took three PRs
Worth recording, since the chain is instructive:
</body>and extracted as an empty string — but not this symptom. I diagnosed it from thetruncated: trueflag in the live response without checking whether the body actually lacked the tag. It did not.I verified each one against prod after it deployed rather than assuming, which is the only reason the second and third links were found at all.