Files
gitea/modules/egress/policies_test.go
T
TheFox0x7 1b1274486c fix(git)!: use internal proxy for all git operations (#39426)
Introduces gitproxy module which spawns a small forward proxy as scanner
for git calls
Replaces hostmatcher with matchlist which supports port rules
Deprecates ALLOWED_DOMAINS/BLOCKED_DOMAINS and ALLOW_LOCALNETWORKS
settings in migration in favor of full names we have in security
configs.
Removes `external` preset in favor of lax/strict modes, strict mode
requiring explicit ports if they aren't standard http/s ones.

Breaking changes:
- `external` preset no longer works as deny rule. To enforce that, use
`strict` mode and allow ranges to connect to
- Wildcards are no longer accepted in IP addresses
- `*` is no longer allowed as entry in lists
- domain rules now use curl like syntax `*.example.com` matching
subdomains but not `example.com`, `example.com` matching itself and all
subdomains. `example.*` is not a valid rule
- In the default `lax` mode, `[security] ALLOWED_HOST_LIST` no longer
restricts public hosts, set `EGRESS_MODE = strict` to keep an exclusive
list. A startup warning flags this
- Invalid list entries are logged at startup, invalid
`BLOCKED_HOST_LIST`/`BLOCKED_DOMAINS` entries stop it

Docs: https://gitea.com/gitea/docs/pulls/557
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-09-29 14:43:36 +02:00

101 lines
3.8 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package egress
import (
"net/http"
"net/url"
"testing"
"gitea.dev/modules/setting"
"gitea.dev/modules/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func mustURL(t *testing.T, raw string) *url.URL {
t.Helper()
u, err := url.Parse(raw)
require.NoError(t, err)
return u
}
func TestNewMigrationPolicy(t *testing.T) {
defer test.MockVariableValue(&setting.Migrations)()
for _, tc := range []struct {
allow, block, mode, target string
want bool
}{
{target: "https://1.2.3.4", want: true},
{allow: "github.com", target: "https://10.0.0.1"}, // a hostname allow doesn't cover a private IP
{allow: "github.com", target: "https://8.8.8.8", want: true}, // lax exempts public targets
{allow: "github.com", mode: "strict", target: "https://8.8.8.8"},
{block: "8.8.0.0/16", target: "https://8.8.8.8"},
} {
setting.Migrations.AllowedHostList, setting.Migrations.BlockedHostList, setting.Migrations.EgressMode = tc.allow, tc.block, tc.mode
u, err := url.Parse(tc.target)
require.NoError(t, err)
err = NewMigrationPolicy().CheckHostIPs(u)
assert.Equal(t, tc.want, err == nil, "%+v: %v", tc, err)
}
}
func TestWebhookPolicyProxy(t *testing.T) {
proxyURL := &url.URL{Scheme: "http", Host: "localhost:8080"}
defer test.MockVariableValue(&setting.Security.EgressMode, "lax")()
defer test.MockVariableValue(&setting.Webhook.AllowedHostList, "discordapp.com,s.discordapp.com")()
defer test.MockVariableValue(&setting.Webhook.ProxyURL, proxyURL.String())()
defer test.MockVariableValue(&setting.Webhook.ProxyURLFixed, proxyURL)()
defer test.MockVariableValue(&setting.Webhook.ProxyHosts, []string{"*.discordapp.com", "discordapp.com"})()
selectProxy := NewWebhookPolicy().NewHTTPTransport().Proxy
for target, want := range map[string]string{
"https://discordapp.com/api/webhooks/xxxxxxxxx/xxxxxxxxxxxxxxxxxxx": proxyURL.String(),
"http://s.discordapp.com/assets/xxxxxx": proxyURL.String(),
"http://github.com/a/b": "",
"http://www.discordapp.com/assets/xxxxxx": proxyURL.String(),
} {
req, err := http.NewRequest(http.MethodPost, target, nil)
require.NoError(t, err)
req.Host = ""
u, err := selectProxy(req)
require.NoError(t, err, target)
if want == "" {
assert.Nil(t, u, target)
} else {
assert.Equal(t, want, u.String(), target)
}
}
}
func TestSecurityPolicy(t *testing.T) {
defer test.MockVariableValue(&setting.Security.AllowedHostList, "avatars.example.com")()
defer test.MockVariableValue(&setting.Security.EgressMode, "lax")()
lax := NewSecurityPolicy("test")
assert.NoError(t, lax.CheckHost(mustURL(t, "https://avatars.example.com")))
assert.NoError(t, lax.CheckHost(mustURL(t, "https://8.8.8.8"))) // lax exempts public targets
assert.Error(t, lax.CheckHost(mustURL(t, "https://10.0.0.1"))) // restricted targets still need an allow entry
setting.Security.EgressMode = "strict"
strict := NewSecurityPolicy("test")
assert.NoError(t, strict.CheckHost(mustURL(t, "https://avatars.example.com")))
assert.Error(t, strict.CheckHost(mustURL(t, "https://8.8.8.8")))
}
func TestNewGitPolicy(t *testing.T) {
gitConfig := map[string]string{"http.proxy": "proxy.corp"}
defer test.MockVariableValue(&setting.GitConfig.Options, gitConfig)()
gitPolicy, err := NewGitPolicy()
require.NoError(t, err)
selected, err := gitPolicy.Proxy(&http.Request{URL: &url.URL{Scheme: "https", Host: "git.example.com"}})
require.NoError(t, err)
assert.Equal(t, "http://proxy.corp:1080", selected.String())
gitConfig["http.proxy"] = "http://user:secret@[::1"
_, err = NewGitPolicy()
require.Error(t, err)
assert.NotContains(t, err.Error(), "secret")
}