Commit Graph
4 Commits
Author SHA1 Message Date
sneak 433fdceee2 Say max_retries is the total attempt count, not a retry count (closes #316)
check / check (push) Failing after 1s
The delivery core makes max_retries attempts in total: a fresh delivery
starts at attempt one and gives up once the attempt number reaches
max_retries, so 3 is three attempts, not four, and 0 is special-cased to
a single fire-and-forget attempt with no retries and no circuit breaker.
The create and edit target forms called it "Max retries" with no total,
and the README data-model row called it "maximum retry attempts", so an
operator wanting "try, then retry twice" would enter the wrong number.

Both forms and the README rows now state the number is the total number
of delivery attempts, with the 0 case spelled out. The delivery
arithmetic is unchanged. A UI copy test renders both forms and pins the
shared wording so it cannot drift back to a retry count.

Model: opus-4-8
2026-09-21 07:55:07 +00:00
clawbot 37b59f8822 Remove inbound request signature verification (closes #279)
check / check (push) Successful in 3m14s
2026-08-24 03:25:09 +02:00
clawbot fcead5d401 Add optional inbound webhook signature verification (closes #67) (#228)
check / check (push) Superseded by a newer commit; never tested
The receiver had no inbound authentication of any kind: /webhook/{uuid}
was mounted behind a rate limiter alone, so the only thing protecting an
entrypoint was the secrecy of a v4 UUID in a URL path. Inbound headers are
forwarded almost verbatim to the target, so anyone who learned the URL
also chose the headers the downstream service received.

Adds an optional per-entrypoint secret with two schemes: github
(X-Hub-Signature-256, HMAC-SHA256 hex over the raw body) and gitlab
(X-Gitlab-Token, a plain shared token). Comparison is constant-time, the
HMAC is computed over the raw body before any parsing, and rejection
happens before persistence -- an unauthenticated request creates no event
row. An entrypoint with no secret behaves exactly as before, including
every row that predates this change.

The scheme's credential header is stripped from the header map before it
is marshalled into Event.Headers, so the GitLab token reaches neither the
event store nor any delivery target. SchemeInfo.HeaderIsDigest defaults to
false meaning strip, so a scheme added later is protected unless its
header is positively declared a digest.
2026-08-20 08:01:32 +02:00
clawbot aab448b076 Clarify web UI terminology, copy, and the entrypoint URL (closes #57)
check / check (push) Successful in 4s
Unifies user-visible copy on "Webhook" (routes and URLs unchanged), drops
the placeholder Profile settings section, and adds a copy-to-clipboard
affordance for the entrypoint URL as progressive enhancement — the button
stays hidden unless both the target element and the Clipboard API resolve,
so no dead control appears without JavaScript and the URL stays selectable.

Retention copy now matches what the code does: deletion is permanent, 0
retains forever, and a blank field means the default on create or the
current value on edit. The permanent-deletion sentence is suppressed for a
retain-forever webhook, which the reaper exempts before computing a cutoff.

Template tests gained a render-completed assertion. Without it, a page that
aborted mid-render still satisfied assertions matching the already-flushed
prefix, because renderTemplate streams to the ResponseWriter (#123).
2026-08-11 15:42:08 +02:00