- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package fetchguard
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Gap (f): PublicOnlyMode private-IP rejection is already asserted by
|
|
// TestFetchPrivateIPBlockedInBothModes/PublicOnlyMode. This file adds
|
|
// PublicOnlyMode accepting any host when the dial-time IP check is
|
|
// satisfied (loopback httptest with skipReservedCheck — a live public
|
|
// IP dial would require outbound network and is not asserted here).
|
|
|
|
func TestFetchPublicOnlyModeAcceptsAnyHostWhenPublic(t *testing.T) {
|
|
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
io.WriteString(w, "ok")
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
res, err := Fetch(t.Context(), srv.URL, withTestLoopback(srv, Policy{
|
|
Mode: PublicOnlyMode,
|
|
MaxBytes: 1024,
|
|
Timeout: 2 * time.Second,
|
|
}), nil)
|
|
if err != nil {
|
|
t.Fatalf("PublicOnlyMode must accept the httptest host: %v", err)
|
|
}
|
|
if string(res.Body) != "ok" {
|
|
t.Fatalf("body = %q", res.Body)
|
|
}
|
|
}
|
|
|
|
func TestFetchPublicOnlyModePrivateIPRejected(t *testing.T) {
|
|
// Explicit restatement of the private-IP case under PublicOnlyMode so
|
|
// this coverage file names both halves of gap (f).
|
|
srv := httptest.NewTLSServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
|
|
t.Error("handler must not run for a private dial")
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
_, err := Fetch(t.Context(), srv.URL, Policy{
|
|
Mode: PublicOnlyMode,
|
|
Timeout: 2 * time.Second,
|
|
MaxBytes: 1024,
|
|
}, nil)
|
|
if reasonFrom(t, err) != ReasonPrivateIP {
|
|
t.Fatalf("reason = %q, want %s", reasonFrom(t, err), ReasonPrivateIP)
|
|
}
|
|
}
|
|
|
|
func TestHostAllowedExactAndDottedSuffix(t *testing.T) {
|
|
allowed := []string{"discogs.com", ""}
|
|
if !hostAllowed("discogs.com", allowed) {
|
|
t.Fatal("exact match")
|
|
}
|
|
if !hostAllowed("api.discogs.com", allowed) {
|
|
t.Fatal("dotted-suffix match")
|
|
}
|
|
if hostAllowed("evil-discogs.com", allowed) {
|
|
t.Fatal("raw suffix must not match")
|
|
}
|
|
if hostAllowed("example.test", allowed) {
|
|
t.Fatal("unrelated host")
|
|
}
|
|
}
|
|
|
|
func TestMapTransportErrorReasons(t *testing.T) {
|
|
if got := mapTransportError(errPrivateIP); got.Reason != ReasonPrivateIP {
|
|
t.Fatalf("private_ip = %s", got.Reason)
|
|
}
|
|
dns := &net.DNSError{Err: "no such host", Name: "nope.test", IsNotFound: true}
|
|
if got := mapTransportError(dns); got.Reason != ReasonUnresolvable {
|
|
t.Fatalf("dns = %s", got.Reason)
|
|
}
|
|
if got := mapTransportError(errors.New("connection reset")); got.Reason != ReasonNetworkError {
|
|
t.Fatalf("other = %s", got.Reason)
|
|
}
|
|
}
|
|
|
|
func TestErrorStringWithoutInner(t *testing.T) {
|
|
e := &Error{Reason: ReasonScheme}
|
|
if e.Error() != "fetchguard: scheme" {
|
|
t.Fatalf("Error() = %q", e.Error())
|
|
}
|
|
var nilE *Error
|
|
if nilE.Error() != "fetchguard: error" {
|
|
t.Fatalf("nil Error() = %q", nilE.Error())
|
|
}
|
|
if nilE.Unwrap() != nil {
|
|
t.Fatal("nil Unwrap")
|
|
}
|
|
}
|