Found during the rework of #242 and deliberately not fixed there — it predates that PR and is outside the scope of #233 and #243. Not milestoned for 1.0; filed so it is on the record rather than only in a PR comment.
applyRequestHeaders sets Content-Type from event.ContentType, then Adds the inbound Content-Type that the forwarded event header map also carries. The outbound request can therefore go out with two Content-Type values.
Definition of done:
An outbound delivery carries exactly one Content-Type when the inbound event supplied one and event.ContentType is also set.
A test asserts the outbound request has exactly one value for the header, covering both the agreeing and disagreeing cases.
Which value wins is stated explicitly in the fix rather than left to map iteration order.
Found during the rework of https://git.eeqj.de/sneak/webhooker/pulls/242 and deliberately not fixed there — it predates that PR and is outside the scope of https://git.eeqj.de/sneak/webhooker/issues/233 and https://git.eeqj.de/sneak/webhooker/issues/243. Not milestoned for 1.0; filed so it is on the record rather than only in a PR comment.
`applyRequestHeaders` sets `Content-Type` from `event.ContentType`, then `Add`s the inbound `Content-Type` that the forwarded event header map also carries. The outbound request can therefore go out with two `Content-Type` values.
Definition of done:
- An outbound delivery carries exactly one `Content-Type` when the inbound event supplied one and `event.ContentType` is also set.
- A test asserts the outbound request has exactly one value for the header, covering both the agreeing and disagreeing cases.
- Which value wins is stated explicitly in the fix rather than left to map iteration order.
Plan. The code the issue names is still on next (3cdab97). applyRequestHeaders (internal/delivery/target_http.go) calls Set on Content-Type from event.ContentType. forwardEventHeaders then calls Add on every forwardable inbound header, and the inbound Content-Type is one of them.
Precedence, stated in a comment at applyRequestHeaders:
A Content-Type the operator configured on the target wins.
Otherwise the event's ContentType, which describes the stored body being sent.
Otherwise nothing.
An inbound Content-Type is never forwarded as a second value. The receiver already sets event.ContentType from the inbound header (internal/handlers/webhook.go), so nothing is lost.
Fix: the plainest is to make forwardEventHeaders skip Content-Type and let applyRequestHeaders set it. Keep the redirect handling as it is: the existing delete(originScoped, "Content-Type") exists so a 307/308 does not strip the body's type. Check that it still holds.
Tests: the outbound request has exactly one Content-Type value, in each of these cases:
the inbound value and event.ContentType agree;
they disagree (the event's wins);
the event has none (no Content-Type is sent, even if the stored inbound headers carry one);
the target configures its own (that one wins).
Each case fails when the fix is removed.
Model: opus-5-5
Plan. The code the issue names is still on `next` (`3cdab97`). `applyRequestHeaders` (`internal/delivery/target_http.go`) calls `Set` on `Content-Type` from `event.ContentType`. `forwardEventHeaders` then calls `Add` on every forwardable inbound header, and the inbound `Content-Type` is one of them.
- **Precedence, stated in a comment at `applyRequestHeaders`:**
1. A `Content-Type` the operator configured on the target wins.
2. Otherwise the event's `ContentType`, which describes the stored body being sent.
3. Otherwise nothing.
An inbound `Content-Type` is never forwarded as a second value. The receiver already sets `event.ContentType` from the inbound header (`internal/handlers/webhook.go`), so nothing is lost.
- **Fix:** the plainest is to make `forwardEventHeaders` skip `Content-Type` and let `applyRequestHeaders` set it. Keep the redirect handling as it is: the existing `delete(originScoped, "Content-Type")` exists so a 307/308 does not strip the body's type. Check that it still holds.
- **Tests:** the outbound request has exactly one `Content-Type` value, in each of these cases:
- the inbound value and `event.ContentType` agree;
- they disagree (the event's wins);
- the event has none (no `Content-Type` is sent, even if the stored inbound headers carry one);
- the target configures its own (that one wins).
Each case fails when the fix is removed.
Model: opus-5-5
clawbot
self-assigned this 2026-09-29 04:31:40 +02:00
Built in #331: the inbound Content-Type is no longer copied from the stored headers, and applyRequestHeaders states which value wins (a Content-Type configured on the target, then the event's ContentType, then none). A test covers the four cases in the plan.
Model: opus-5-5
Built in https://git.eeqj.de/sneak/webhooker/pulls/331: the inbound `Content-Type` is no longer copied from the stored headers, and `applyRequestHeaders` states which value wins (a `Content-Type` configured on the target, then the event's `ContentType`, then none). A test covers the four cases in the plan.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found during the rework of #242 and deliberately not fixed there — it predates that PR and is outside the scope of #233 and #243. Not milestoned for 1.0; filed so it is on the record rather than only in a PR comment.
applyRequestHeaderssetsContent-Typefromevent.ContentType, thenAdds the inboundContent-Typethat the forwarded event header map also carries. The outbound request can therefore go out with twoContent-Typevalues.Definition of done:
Content-Typewhen the inbound event supplied one andevent.ContentTypeis also set.clawbot referenced this issue2026-08-20 11:07:50 +02:00
Plan. The code the issue names is still on
next(3cdab97).applyRequestHeaders(internal/delivery/target_http.go) callsSetonContent-Typefromevent.ContentType.forwardEventHeadersthen callsAddon every forwardable inbound header, and the inboundContent-Typeis one of them.Precedence, stated in a comment at
applyRequestHeaders:Content-Typethe operator configured on the target wins.ContentType, which describes the stored body being sent.An inbound
Content-Typeis never forwarded as a second value. The receiver already setsevent.ContentTypefrom the inbound header (internal/handlers/webhook.go), so nothing is lost.Fix: the plainest is to make
forwardEventHeadersskipContent-Typeand letapplyRequestHeadersset it. Keep the redirect handling as it is: the existingdelete(originScoped, "Content-Type")exists so a 307/308 does not strip the body's type. Check that it still holds.Tests: the outbound request has exactly one
Content-Typevalue, in each of these cases:event.ContentTypeagree;Content-Typeis sent, even if the stored inbound headers carry one);Each case fails when the fix is removed.
Model: opus-5-5
Built in #331: the inbound
Content-Typeis no longer copied from the stored headers, andapplyRequestHeadersstates which value wins (aContent-Typeconfigured on the target, then the event'sContentType, then none). A test covers the four cases in the plan.Model: opus-5-5