[ENG-4057] Share one outbound guard between protections and release it on stop - #300
Merged
Merged
Conversation
fetch and node:http(s) are process-wide, so every protection with egress enabled now registers its own screen with one shared guard. A call is refused when any registered screen refuses it, and each protection reports its own refusals. Uninstalling removes only that protection's screen; the last one out restores the original functions. protection.stop() now uninstalls the protection's screen too. A fetch call whose arguments the runtime's Request rejects is still screened when its destination can be read, and is counted as an unscreened call when it cannot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Cohesive implementation of a shared egress guard with thorough lifecycle handling. 🎯 Quality: 87% Excellent · 📦 Size: Large — consider splitting if possible 🛡️ Standards: Not checked — 404 lines changed, over your team's 400-line limit, and nothing checked before it was opened. Coding agents can call the 🤖 Authorship: Agent-written — Claude Code, going by its own attribution. Whether a person read it is unknown; coding agents can call the 📈 This month: Your 161st PR — above team average · Averaging Good |
stopRefresh() now stops only the rule refresh: the poll loop and its recovery retries. The reporters and the protection's outbound screening keep running; stop() still ends everything, including removing the outbound screen. Test cleanups that relied on the full shutdown now call stop(). Docs and declarations now say that when several protections screen outbound calls, any one of them can refuse a call, so one protection's allowHosts does not override another's refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
/review |
daniloradovic
approved these changes
Sep 29, 2026
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.
Outbound request screening now works the same way however many protections a process creates.
Shared guard.
fetchandnode:http/node:httpsare process-wide, so each protection created withegress: truenow registers its own screen with one shared guard.onEgressBlockand detections. A host in one protection'sallowHostsis still refused when another protection refuses it.node:httppath, a hostname is resolved once, and that resolution is checked by every screen that resolves the host. The connection is then pinned to addresses all of those screens accepted. A screen whoseallowHostslists the host still skips that host's DNS check, as before.uninstallEgress()removes only that protection's screen. When the last screen leaves, the original functions are restored. As before, a wrapper that another library layered on top is never overwritten.stop()andstopRefresh().protection.stop()now also removes the protection's outbound screen. A protection created after another has stopped screens with its own rules.protection.stopRefresh()stops only the rule refresh: the poll loop and its recovery retries. Outbound screening and the reporters keep running. It used to be an alias ofstop(), so test cleanups that relied on the full shutdown now callstop().AGENT-INSTALL.mdand the type declarations describe both.Unusual
fetchinput. Afetchcall whose arguments the runtime'sRequestrejects is still handed to the underlyingfetchunchanged. Its destination is now screened when it can be read (a URL string, a URL, or an object withurlorhref). When it cannot be read, the call is counted as an unscreenedegress:unrecognised-requestskip.Validation: full suite (3,445 passed, 7 skipped), typecheck, build, and
capabilities:check.Field test outstanding. This changes
AGENT-INSTALL.md, so the hostile field test must run immediately after the release that contains it. A run before that release would inspect the previously published docs, so it can't gate this change. Until then, the disclosure tests andcapabilities:checkare what cover the wording.Refs ENG-4057
🤖 Generated with Claude Code