feat(hooks): add http_post builtin#2705
Merged
dgageot merged 2 commits intodocker:mainfrom May 7, 2026
Merged
Conversation
aheritier
approved these changes
May 7, 2026
Contributor
aheritier
left a comment
There was a problem hiding this comment.
LGTM. Tight, security-conscious primitive.
Strong points:
- Correct use of
httpclient.NewSafeClient— SSRF dial-time protection (loopback / RFC1918 / link-local incl. 169.254.169.254) and bounded 10-hop redirect chain. - Scheme allowlist + non-empty
Hostcheck rejectsfile://,javascript:, scheme-less, and host-less inputs. - Body drain capped at 64 KiB via
io.LimitReader— DoS-safe. target.Redacted()before logging — no userinfo leaked into logs.- Errors and non-2xx swallowed by design (fire-and-forget webhook), with
slog.WarnContextso operators still see them. - Test-only
export_test.go+TestMainto swap the SSRF dialer forhttptestis the right pattern — the unsafe path doesn't compile into release binaries. - Test matrix is complete: happy path, empty body, no-op, swallowed network/HTTP errors, scheme rejection, ctx cancellation.
Non-blocking observations (no action needed):
Content-Type: application/jsonis hardcoded. Fine for the documented use case, but worth keeping in mind if a future caller needsapplication/x-www-form-urlencodedfor legacy webhooks.- The "only http(s) URLs are supported" error message covers both parse failures and disallowed schemes. Slightly less precise than splitting them, but the test contract pins the substring so leave it.
|
❌ PR Review Failed — The review agent encountered an error and could not complete the review. View logs. |
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.
Adds a tiny generic
http_postbuiltin hook underpkg/hooks/builtins/.Behaviour
[url, body?]— first arg is the target URL, optional second arg is the request body sent verbatim withContent-Type: application/json.max_iterations).http(s)/ scheme-less / host-less / unparseable URLs surface as a config error soon_error: warnflags the misconfig.Timeout: 30sis a backstop.Hooks that need fail-closed webhook semantics (billing guards, pre-tool-use gates) belong in a
type: commandentry that can shape the failure mode itself; this builtin trades fidelity for never being the reason an agent run dies.Security hardening
httpclient.NewSafeClient— refuses connections to non-public IPs at dial time (defeating DNS rebinding to loopback / RFC1918 / link-local incl.169.254.169.254cloud metadata) and bounds redirects at 10 hops.http/httpsonly, parsed upfront withnet/url.file://,ftp://,javascript:, etc. are rejected before any I/O.target.Redacted(), so webhook URLs withuser:pass@hostor secret-bearing query strings don't leak to logs.io.LimitReader(_, 64 KiB)so a malicious receiver returning a huge response can't pin the goroutine on an unbounded read.Tests
Six tests covering the happy path, empty-body pings, no-op-on-empty-URL, swallowed server / network errors, scheme + host rejection, and prompt return on
ctxdeadline.TestMainswaps in the unsafe httpclient variant for the test binary sohttptest.NewServer(which binds to127.0.0.1) keeps working — production callers always go through the safe client.