Files
Gitea/services/repository/repository_test.go
T
Giteabot de4b8277e9 fix: various security fixes (#38406) (#38426)
Backport #38406 by @bircni

Addresses a batch of privately reported security issues, grouped by
area:

- **SSRF** - migration PR-patch/asset fetches, OAuth2 avatar & OpenID
discovery, pull-mirror URL re-validation, and the outbound proxy path.
- **Access-token scope** - prevent scope escalation on token creation;
keep public-only tokens confined (feeds, packages, Actions listings,
star/watch lists, limited/private owners).
- **Access control / disclosure** - go-get default-branch leak, webhook
authorization-header leak, watch clearing on private transitions,
label/attachment scoping.
- **Denial of service** - input bounds for npm dist-tags, Debian control
files, Arch file lists, and SSH keys.

### 📌 Attention for site admins

Not breaking - existing configs keep working - but two changes are worth
a look:

- **New SSRF protection** Outbound requests (migrations, OAuth2 avatars,
OpenID discovery, pull mirrors, proxy path) are now validated against
the allow/block host lists. If your instance legitimately reaches
internal hosts, you may need to add them to
`[security].ALLOWED_HOST_LIST` (and the relevant `ALLOW_LOCALNETWORKS`
settings).
- **Deprecation** `[webhook].ALLOWED_HOST_LIST` is deprecated and will
be removed in a future release. Use `[security].ALLOWED_HOST_LIST`
instead; the old key still works for now.

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
2026-07-12 17:41:58 +00:00

116 lines
3.5 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repository
import (
"testing"
activities_model "gitea.dev/models/activities"
"gitea.dev/models/db"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
"gitea.dev/models/unittest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAttachLinkedTypeAndRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
testCases := []struct {
name string
attachID int64
expectedUnitType unit.Type
expectedRepoID int64
}{
{"LinkedIssue", 1, unit.TypeIssues, 1},
{"LinkedComment", 3, unit.TypePullRequests, 1},
{"LinkedRelease", 9, unit.TypeReleases, 1},
{"Notlinked", 10, unit.TypeInvalid, 0},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
attach, err := repo_model.GetAttachmentByID(t.Context(), tc.attachID)
assert.NoError(t, err)
unitType, repoID, err := GetAttachmentLinkedTypeAndRepoID(t.Context(), attach)
assert.NoError(t, err)
assert.Equal(t, tc.expectedUnitType, unitType)
assert.Equal(t, tc.expectedRepoID, repoID)
})
}
}
func TestUpdateRepositoryVisibilityChanged(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// Get sample repo and change visibility
repo, err := repo_model.GetRepositoryByID(t.Context(), 9)
assert.NoError(t, err)
repo.IsPrivate = true
// Update it
err = updateRepository(t.Context(), repo, true)
assert.NoError(t, err)
// Check visibility of action has become private
act := activities_model.Action{}
_, err = db.GetEngine(t.Context()).ID(3).Get(&act)
assert.NoError(t, err)
assert.True(t, act.IsPrivate)
}
func TestRepository_HasWiki(t *testing.T) {
unittest.PrepareTestEnv(t)
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.True(t, HasWiki(t.Context(), repo1))
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
assert.False(t, HasWiki(t.Context(), repo2))
}
func TestMakeRepoPrivateClearsWatches(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.False(t, repo.IsPrivate)
watchers, err := repo_model.GetRepoWatchersIDs(t.Context(), repo.ID)
require.NoError(t, err)
require.NotEmpty(t, watchers)
assert.NoError(t, MakeRepoPrivate(t.Context(), repo, true))
watchers, err = repo_model.GetRepoWatchersIDs(t.Context(), repo.ID)
assert.NoError(t, err)
assert.Empty(t, watchers)
updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.True(t, updatedRepo.IsPrivate)
assert.Zero(t, updatedRepo.NumWatches)
}
// TestUpdateRepositoryClearsWatchesOnVisibilityChange ensures the shared updateRepository
// helper (used by the API EditRepo path) also clears watches when a repo goes private.
func TestUpdateRepositoryClearsWatchesOnVisibilityChange(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.False(t, repo.IsPrivate)
watchers, err := repo_model.GetRepoWatchersIDs(t.Context(), repo.ID)
require.NoError(t, err)
require.NotEmpty(t, watchers)
repo.IsPrivate = true
require.NoError(t, updateRepository(t.Context(), repo, true))
watchers, err = repo_model.GetRepoWatchersIDs(t.Context(), repo.ID)
assert.NoError(t, err)
assert.Empty(t, watchers)
updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID})
assert.Zero(t, updatedRepo.NumWatches)
}