Files
webhooker/internal/handlers/target_private_refusal_test.go
T
clawbot 2d2d5f6e20
check / check (push) Waiting to run
Keep what was typed when a target or webhook edit is refused (closes #381)
A refused save on the target edit page now shows the edit form again,
with the reason above it and every value submitted, instead of a bare
text page; the status codes are unchanged. The webhook edit page keeps
the submitted name, description and retention the same way, while the
page still reports the stored retention.

Target edits are validated by setTargetFromForm, which newTarget now
uses too, so the add and edit forms accept and refuse the same things.
An empty max_retries keeps the target's own count.

The browser test also saves both edit pages with refused values. Its
seeding and its table of target types move into helpers, leaving the
test function a plain list of check calls.

Model: opus-5-5
2026-10-02 22:41:28 +00:00

123 lines
3.1 KiB
Go

package handlers_test
import (
"html"
"net/http"
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sneak.berlin/go/webhooker/internal/database"
)
// privateRefusalHint is the sentence that tells an operator a private
// destination is refused on purpose, and how to allow one.
const privateRefusalHint = "Private and reserved addresses are " +
"refused by default; the server's ALLOWED_EGRESS_CIDRS setting " +
"allows named networks (see \"Allowing egress to your own " +
"network\" in the README)."
// TestTargetRefusal_PrivateDestinationSaysHowToAllowIt covers both
// target types that take a URL, on add and on edit.
func TestTargetRefusal_PrivateDestinationSaysHowToAllowIt(
t *testing.T,
) {
t.Parallel()
env := setupSourceTest(t)
targetTypes := []database.TargetType{
database.TargetTypeHTTP,
database.TargetTypeSlack,
}
for _, targetType := range targetTypes {
t.Run(string(targetType), func(t *testing.T) {
t.Parallel()
webhook := seedWebhookWithRetention(t, env.db, 30)
targetsPath := "/hook/" + webhook.ID + "/targets"
form := url.Values{}
form.Set("name", "private")
form.Set("type", string(targetType))
form.Set("url", editBlockedURL)
// A refused add shows the webhook page again, and a
// refused edit the edit page, where the hint is
// HTML-escaped.
added := serveTarget(
env, http.MethodPost, targetsPath, form,
)
assert.Equal(t, http.StatusBadRequest, added.Code)
assert.Contains(
t, added.Body.String(),
html.EscapeString(privateRefusalHint),
)
form.Set("url", editOriginalURL)
created := serveTarget(
env, http.MethodPost, targetsPath, form,
)
require.Equal(
t, http.StatusSeeOther, created.Code,
created.Body.String(),
)
targets := targetsForWebhook(t, env.db, webhook.ID)
require.Len(t, targets, 1)
form.Set("url", editBlockedURL)
edited := submitTargetEdit(
env, webhook.ID, targets[0].ID, form,
)
assert.Equal(t, http.StatusBadRequest, edited.Code)
assert.Contains(
t, edited.Body.String(),
html.EscapeString(privateRefusalHint),
)
})
}
}
// TestTargetRefusal_MetadataDestinationDoesNotSayHowToAllowIt: no
// setting opens a link-local address, and Azure's WireServer hands out
// VM credentials, so neither refusal points at the setting.
func TestTargetRefusal_MetadataDestinationDoesNotSayHowToAllowIt(
t *testing.T,
) {
t.Parallel()
env := setupSourceTest(t)
metadataURLs := map[string]string{
"link-local": "http://169.254.169.254/latest/meta-data/",
"wireserver": "http://168.63.129.16/?comp=versions",
}
for name, metadataURL := range metadataURLs {
t.Run(name, func(t *testing.T) {
t.Parallel()
webhook := seedWebhookWithRetention(t, env.db, 30)
form := url.Values{}
form.Set("name", "metadata")
form.Set("type", string(database.TargetTypeHTTP))
form.Set("url", metadataURL)
w := serveTarget(
env, http.MethodPost,
"/hook/"+webhook.ID+"/targets", form,
)
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.NotContains(
t, w.Body.String(), privateRefusalHint,
)
})
}
}