Owner's decision, 2026-08-24, verbatim: "remove all the inbound request signing crap. the uuid url is the authentication secret."
This reverses #67, which landed in fcead5d on next. The entrypoint URL is a capability: possession of the UUID authorises submission. Signature verification is removed, not made optional.
Pre-1.0, no installed base, no stored data anywhere. This is a straight deletion — no migration, no compatibility path, no data cleanup.
Definition of done
Delete the internal/signature package.
The receiver verifies nothing inbound. A valid entrypoint UUID is sufficient.
Remove signature_scheme and signature_secret from the Entrypoint model, the create and edit forms, and every template.
Remove the config knobs the feature added.
README: remove every mention of inbound signature verification. Add a brief, plain statement that the entrypoint URL is the authentication secret and that rotating it means recreating the entrypoint. No threat-model discussion.
Keep the receiver's other protections: the 1 MB body cap, per-IP rate limiting, and the 410 for a disabled entrypoint.
Grep exhaustively — no dead form field, test fixture, config key or README paragraph survives.
Closes #67 and #241 (#241 is entirely about the forwarding consequences of a signature this removes).
Do NOT add masking or redaction of entrypoint UUIDs anywhere — live UUIDs in /metrics and Sentry are acceptable per the owner. #254 and #179 stay exactly as landed.
Verification
make check green.
An unsigned POST to a valid entrypoint returns 200 and is delivered to a sink, on a running instance.
The 1 MB cap, rate limiting and the disabled-entrypoint 410 still work.
A grep showing no trace of signature verification survives.
Owner's decision, 2026-08-24, verbatim: "remove all the inbound request signing crap. the uuid url is the authentication secret."
This reverses https://git.eeqj.de/sneak/webhooker/issues/67, which landed in `fcead5d` on `next`. The entrypoint URL is a capability: possession of the UUID authorises submission. Signature verification is removed, not made optional.
Pre-1.0, no installed base, no stored data anywhere. This is a straight deletion — no migration, no compatibility path, no data cleanup.
## Definition of done
- Delete the `internal/signature` package.
- The receiver verifies nothing inbound. A valid entrypoint UUID is sufficient.
- Remove `signature_scheme` and `signature_secret` from the `Entrypoint` model, the create and edit forms, and every template.
- Remove the config knobs the feature added.
- README: remove every mention of inbound signature verification. Add a brief, plain statement that the entrypoint URL is the authentication secret and that rotating it means recreating the entrypoint. No threat-model discussion.
- Keep the receiver's other protections: the 1 MB body cap, per-IP rate limiting, and the `410` for a disabled entrypoint.
- Grep exhaustively — no dead form field, test fixture, config key or README paragraph survives.
Closes https://git.eeqj.de/sneak/webhooker/issues/67 and https://git.eeqj.de/sneak/webhooker/issues/241 (#241 is entirely about the forwarding consequences of a signature this removes).
Do NOT add masking or redaction of entrypoint UUIDs anywhere — live UUIDs in `/metrics` and Sentry are acceptable per the owner. https://git.eeqj.de/sneak/webhooker/issues/254 and https://git.eeqj.de/sneak/webhooker/issues/179 stay exactly as landed.
## Verification
- `make check` green.
- An unsigned POST to a valid entrypoint returns 200 and is delivered to a sink, on a running instance.
- The 1 MB cap, rate limiting and the disabled-entrypoint 410 still work.
- A grep showing no trace of signature verification survives.
clawbot
added this to the 1.0.0 milestone 2026-08-24 02:58:40 +02:00
Owner ruling, 2026-08-24, on the "what this makes load-bearing" section above: live entrypoint UUIDs appearing in /metrics and in Sentry payloads are acceptable. That section overstated the concern — disregard it.
Concretely, for anyone implementing this or reading it later:
Do NOT add masking, redaction or hashing of entrypoint UUIDs anywhere. Not in metrics, not in Sentry, not in logs. The question has been asked and answered.
#254 stays exactly as it landed. Its fix was never really about UUIDs — it bounded an unauthenticated attacker's ability to mint unbounded Prometheus label cardinality (measured: 182 series to 78,182, never evicted). That is a memory-exhaustion fix and stands entirely on its own. The UUIDs leaving the scrape was incidental.
#179 likewise stays as landed; sending the route pattern rather than the concrete path is correct Sentry practice regardless of what the path contains.
What the README should say is unchanged and simple: the entrypoint URL is the authentication secret, anyone holding it can submit events, and rotation means recreating the entrypoint. State it plainly as the design, without alarm and without a threat-model discussion.
Owner ruling, 2026-08-24, on the "what this makes load-bearing" section above: live entrypoint UUIDs appearing in `/metrics` and in Sentry payloads are **acceptable**. That section overstated the concern — disregard it.
Concretely, for anyone implementing this or reading it later:
- Do NOT add masking, redaction or hashing of entrypoint UUIDs anywhere. Not in metrics, not in Sentry, not in logs. The question has been asked and answered.
- https://git.eeqj.de/sneak/webhooker/issues/254 stays exactly as it landed. Its fix was never really about UUIDs — it bounded an unauthenticated attacker's ability to mint unbounded Prometheus label cardinality (measured: 182 series to 78,182, never evicted). That is a memory-exhaustion fix and stands entirely on its own. The UUIDs leaving the scrape was incidental.
- https://git.eeqj.de/sneak/webhooker/issues/179 likewise stays as landed; sending the route pattern rather than the concrete path is correct Sentry practice regardless of what the path contains.
What the README should say is unchanged and simple: the entrypoint URL is the authentication secret, anyone holding it can submit events, and rotation means recreating the entrypoint. State it plainly as the design, without alarm and without a threat-model discussion.
Plan. Branch issue-279-remove-inbound-signing, base next, one commit.
Straight deletion of everything fcead5d added, keeping the receiver's other guards untouched:
Delete internal/signature/ (package + tests).
internal/database/model_entrypoint.go: drop SignatureScheme type and constants, the SignatureScheme/SignatureSecret fields, and the SignatureConfigured/SignatureHalfConfigured methods. Vestigial columns in an installed base that does not exist are not a problem, so no migration.
internal/handlers/webhook.go: drop verifyInboundSignature and the SanitizeHeaders call. The header map is marshalled as received. readWebhookBody (1 MB cap), the 410 for inactive, and the rate-limit middleware are not touched.
internal/handlers/source_management.go: delete HandleEntrypointSecret, applyEntrypointSecret, storeEntrypointSecret and the SignatureSchemes template datum.
internal/handlers/entrypoint_view.go: drop Configured/Scheme/SchemeLabel/SchemeHeader and the label constants. EntrypointView stays — it is still the display projection.
internal/server/routes.go: drop the POST /source/{id}/entrypoints/{entrypointID}/secret route.
templates/source_detail.html: remove the Signature line, the Configure/Rotate button, the secret form and its showSecret state.
Tests: delete webhook_signature_test.go, entrypoint_secret_test.go, target_http_secret_test.go, migration_entrypoint_test.go; drop the entrypoint cases from model_secrets_test.go and the SignatureSchemes datum from ui_copy_test.go.
README: delete the Inbound Signature Verification section, the two entrypoints columns and their migration note, the /secret route row, the tree entries, the feature-list bullet, the resubmit paragraph and the pipeline step. Add a short statement that the entrypoint URL is the authentication secret and that rotation means recreating the entrypoint.
There are no config keys to remove — the feature never added any.
Not touched: the delivery-side comments in redirect.go, target_redact.go and sentry.go that name X-Hub-Signature/X-Gitlab-Token. Senders still send those headers; those files are about forwarding and redaction, not about verification.
No UUID masking added anywhere.
Verification: make check with GOFLAGS=-count=1, plus a live instance proving an unsigned POST is accepted and delivered, the 1 MB cap, the per-IP rate limit and the disabled-entrypoint 410.
Plan. Branch `issue-279-remove-inbound-signing`, base `next`, one commit.
Straight deletion of everything `fcead5d` added, keeping the receiver's other guards untouched:
- Delete `internal/signature/` (package + tests).
- `internal/database/model_entrypoint.go`: drop `SignatureScheme` type and constants, the `SignatureScheme`/`SignatureSecret` fields, and the `SignatureConfigured`/`SignatureHalfConfigured` methods. Vestigial columns in an installed base that does not exist are not a problem, so no migration.
- `internal/handlers/webhook.go`: drop `verifyInboundSignature` and the `SanitizeHeaders` call. The header map is marshalled as received. `readWebhookBody` (1 MB cap), the `410` for inactive, and the rate-limit middleware are not touched.
- `internal/handlers/source_management.go`: delete `HandleEntrypointSecret`, `applyEntrypointSecret`, `storeEntrypointSecret` and the `SignatureSchemes` template datum.
- `internal/handlers/entrypoint_view.go`: drop `Configured`/`Scheme`/`SchemeLabel`/`SchemeHeader` and the label constants. `EntrypointView` stays — it is still the display projection.
- `internal/server/routes.go`: drop the `POST /source/{id}/entrypoints/{entrypointID}/secret` route.
- `templates/source_detail.html`: remove the Signature line, the Configure/Rotate button, the secret form and its `showSecret` state.
- Tests: delete `webhook_signature_test.go`, `entrypoint_secret_test.go`, `target_http_secret_test.go`, `migration_entrypoint_test.go`; drop the entrypoint cases from `model_secrets_test.go` and the `SignatureSchemes` datum from `ui_copy_test.go`.
- README: delete the `Inbound Signature Verification` section, the two `entrypoints` columns and their migration note, the `/secret` route row, the tree entries, the feature-list bullet, the resubmit paragraph and the pipeline step. Add a short statement that the entrypoint URL is the authentication secret and that rotation means recreating the entrypoint.
There are no config keys to remove — the feature never added any.
Not touched: the delivery-side comments in `redirect.go`, `target_redact.go` and `sentry.go` that name `X-Hub-Signature`/`X-Gitlab-Token`. Senders still send those headers; those files are about forwarding and redaction, not about verification.
No UUID masking added anywhere.
Verification: `make check` with `GOFLAGS=-count=1`, plus a live instance proving an unsigned POST is accepted and delivered, the 1 MB cap, the per-IP rate limit and the disabled-entrypoint `410`.
Done in #281 (branch issue-279-remove-inbound-signing, base next). Details are in the PR body; the verification evidence is below.
make check green with GOFLAGS=-count=1 on the rebased branch: 575 tests, 0 cached, lint in Docker 0 issues.
On a running instance with an HTTP sink target:
Unsigned POST to a valid entrypoint: 200, and the payload arrived at the sink.
POST carrying a deliberately wrong X-Hub-Signature-256 and a wrong X-Gitlab-Token: 200, also delivered. Nothing about the request is checked.
1048575-byte body 200; 1048577-byte body 413 Request body too large — the 1 MB cap holds.
140 POSTs from one IP: 120 accepted, then 429 — the per-IP receiver limit is exactly as before.
POST to a deactivated entrypoint: 410 Gone. Reactivated, the same POST is 200 again.
POST to an unknown UUID: 404.
Grep over the tree finds no surviving signature_scheme, signature_secret, SignatureScheme, SignatureSecret, SanitizeHeaders, HandleEntrypointSecret, verifyInboundSignature or internal/signature in code, templates, config or docs, and no showSecret state or secret form field in any template.
No masking or redaction of entrypoint UUIDs was added anywhere; #254 and #179 are untouched.
Not merged — that is the caller's.
Done in https://git.eeqj.de/sneak/webhooker/pulls/281 (branch `issue-279-remove-inbound-signing`, base `next`). Details are in the PR body; the verification evidence is below.
`make check` green with `GOFLAGS=-count=1` on the rebased branch: 575 tests, 0 cached, lint in Docker `0 issues`.
On a running instance with an HTTP sink target:
- Unsigned POST to a valid entrypoint: `200`, and the payload arrived at the sink.
- POST carrying a deliberately wrong `X-Hub-Signature-256` and a wrong `X-Gitlab-Token`: `200`, also delivered. Nothing about the request is checked.
- 1048575-byte body `200`; 1048577-byte body `413 Request body too large` — the 1 MB cap holds.
- 140 POSTs from one IP: 120 accepted, then `429` — the per-IP receiver limit is exactly as before.
- POST to a deactivated entrypoint: `410 Gone`. Reactivated, the same POST is `200` again.
- POST to an unknown UUID: `404`.
Grep over the tree finds no surviving `signature_scheme`, `signature_secret`, `SignatureScheme`, `SignatureSecret`, `SanitizeHeaders`, `HandleEntrypointSecret`, `verifyInboundSignature` or `internal/signature` in code, templates, config or docs, and no `showSecret` state or secret form field in any template.
No masking or redaction of entrypoint UUIDs was added anywhere; https://git.eeqj.de/sneak/webhooker/issues/254 and https://git.eeqj.de/sneak/webhooker/issues/179 are untouched.
Not merged — that is the caller's.
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.
Owner's decision, 2026-08-24, verbatim: "remove all the inbound request signing crap. the uuid url is the authentication secret."
This reverses #67, which landed in
fcead5donnext. The entrypoint URL is a capability: possession of the UUID authorises submission. Signature verification is removed, not made optional.Pre-1.0, no installed base, no stored data anywhere. This is a straight deletion — no migration, no compatibility path, no data cleanup.
Definition of done
internal/signaturepackage.signature_schemeandsignature_secretfrom theEntrypointmodel, the create and edit forms, and every template.410for a disabled entrypoint.Closes #67 and #241 (#241 is entirely about the forwarding consequences of a signature this removes).
Do NOT add masking or redaction of entrypoint UUIDs anywhere — live UUIDs in
/metricsand Sentry are acceptable per the owner. #254 and #179 stay exactly as landed.Verification
make checkgreen.Owner ruling, 2026-08-24, on the "what this makes load-bearing" section above: live entrypoint UUIDs appearing in
/metricsand in Sentry payloads are acceptable. That section overstated the concern — disregard it.Concretely, for anyone implementing this or reading it later:
What the README should say is unchanged and simple: the entrypoint URL is the authentication secret, anyone holding it can submit events, and rotation means recreating the entrypoint. State it plainly as the design, without alarm and without a threat-model discussion.
Plan. Branch
issue-279-remove-inbound-signing, basenext, one commit.Straight deletion of everything
fcead5dadded, keeping the receiver's other guards untouched:internal/signature/(package + tests).internal/database/model_entrypoint.go: dropSignatureSchemetype and constants, theSignatureScheme/SignatureSecretfields, and theSignatureConfigured/SignatureHalfConfiguredmethods. Vestigial columns in an installed base that does not exist are not a problem, so no migration.internal/handlers/webhook.go: dropverifyInboundSignatureand theSanitizeHeaderscall. The header map is marshalled as received.readWebhookBody(1 MB cap), the410for inactive, and the rate-limit middleware are not touched.internal/handlers/source_management.go: deleteHandleEntrypointSecret,applyEntrypointSecret,storeEntrypointSecretand theSignatureSchemestemplate datum.internal/handlers/entrypoint_view.go: dropConfigured/Scheme/SchemeLabel/SchemeHeaderand the label constants.EntrypointViewstays — it is still the display projection.internal/server/routes.go: drop thePOST /source/{id}/entrypoints/{entrypointID}/secretroute.templates/source_detail.html: remove the Signature line, the Configure/Rotate button, the secret form and itsshowSecretstate.webhook_signature_test.go,entrypoint_secret_test.go,target_http_secret_test.go,migration_entrypoint_test.go; drop the entrypoint cases frommodel_secrets_test.goand theSignatureSchemesdatum fromui_copy_test.go.Inbound Signature Verificationsection, the twoentrypointscolumns and their migration note, the/secretroute row, the tree entries, the feature-list bullet, the resubmit paragraph and the pipeline step. Add a short statement that the entrypoint URL is the authentication secret and that rotation means recreating the entrypoint.There are no config keys to remove — the feature never added any.
Not touched: the delivery-side comments in
redirect.go,target_redact.goandsentry.gothat nameX-Hub-Signature/X-Gitlab-Token. Senders still send those headers; those files are about forwarding and redaction, not about verification.No UUID masking added anywhere.
Verification:
make checkwithGOFLAGS=-count=1, plus a live instance proving an unsigned POST is accepted and delivered, the 1 MB cap, the per-IP rate limit and the disabled-entrypoint410.Done in #281 (branch
issue-279-remove-inbound-signing, basenext). Details are in the PR body; the verification evidence is below.make checkgreen withGOFLAGS=-count=1on the rebased branch: 575 tests, 0 cached, lint in Docker0 issues.On a running instance with an HTTP sink target:
200, and the payload arrived at the sink.X-Hub-Signature-256and a wrongX-Gitlab-Token:200, also delivered. Nothing about the request is checked.200; 1048577-byte body413 Request body too large— the 1 MB cap holds.429— the per-IP receiver limit is exactly as before.410 Gone. Reactivated, the same POST is200again.404.Grep over the tree finds no surviving
signature_scheme,signature_secret,SignatureScheme,SignatureSecret,SanitizeHeaders,HandleEntrypointSecret,verifyInboundSignatureorinternal/signaturein code, templates, config or docs, and noshowSecretstate or secret form field in any template.No masking or redaction of entrypoint UUIDs was added anywhere; #254 and #179 are untouched.
Not merged — that is the caller's.