Files
gitea/cmd/web_test.go
T
petru 471cfdd161
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
Modified - [install] [backup] [database] [recovery] Consolidated database backup and installer recovery support.
- 1 - Add: Gitea now creates timestamped database backup bundles under `[backup].PATH`, exposes the backup schedule in the installer, and surfaces the `database_backup` cron task in admin monitoring.
- 2 - Add: installed instances now use `.gitea-installed` and `.gitea-recovery.ini` to enter email-gated recovery instead of falling back to public install mode when configuration or database access is broken.
- 3 - Mod: the installer recovery flow now covers backup-bundle restore, bundled or manual `app.ini` reuse, uploaded SQL/GZ database restores, and repository-filesystem recovery with source-specific validation, confirmations, and preserved launcher state.
- 4 - Fix: recovery now restores bundled `app.ini` snapshots when needed, discovers backup bundles from both the active backup path and persisted `.gitea-recovery.ini` path, and preserves SMTP and other rebuilt settings correctly when `app.ini` is missing or incomplete.
- 5 - Fix: recovery validation and restore handling now accept either a selected backup bundle or an uploaded SQL/GZ dump, keep sensitive secrets and existing `LFS_JWT_SECRET` when appropriate, clear SQLite restore targets before import, and complete the post-install handoff without redirect loops.
- 6 - Mod: fresh installs now default recovery email authorization to enabled with first-admin fallback, and the install/recovery UI, styling, and EN/RO wording were refined to match the final launcher behavior.

Co-Authored-By: petru @ codex (GPT-5) <codex@openai.com>
(cherry picked from commit 9879caf2292691b0cb521d12e6fee924b066bae2)
2026-06-01 03:56:03 +03:00

147 lines
4.8 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"net/http/httptest"
"os"
"path/filepath"
"testing"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// start edit/add - by petru @ codex
func TestMissingInstalledSQLiteDatabase(t *testing.T) {
oldDatabase := setting.Database
oldInstallLock := setting.InstallLock
oldCustomConf := setting.CustomConf
defer func() {
setting.Database = oldDatabase
setting.InstallLock = oldInstallLock
setting.CustomConf = oldCustomConf
}()
tmpDir := t.TempDir()
setting.CustomConf = filepath.Join(tmpDir, "custom", "conf", "app.ini")
setting.Database.Type = "sqlite3"
setting.Database.Path = filepath.Join(tmpDir, "data", "gitea.db")
setting.InstallLock = false // edit/add - by petru @ codex
missing, err := missingInstalledSQLiteDatabase()
require.NoError(t, err)
assert.False(t, missing)
setting.InstallLock = true
missing, err = missingInstalledSQLiteDatabase()
require.NoError(t, err)
assert.True(t, missing)
require.NoError(t, os.MkdirAll(filepath.Dir(setting.Database.Path), 0o755))
require.NoError(t, os.WriteFile(setting.Database.Path, []byte("db"), 0o600))
missing, err = missingInstalledSQLiteDatabase()
require.NoError(t, err)
assert.False(t, missing)
require.NoError(t, os.Remove(setting.Database.Path))
setting.InstallLock = false
require.NoError(t, os.MkdirAll(filepath.Dir(setting.InstallSentinelPath()), 0o755))
require.NoError(t, os.WriteFile(setting.InstallSentinelPath(), []byte("installed\n"), 0o600))
missing, err = missingInstalledSQLiteDatabase()
require.NoError(t, err)
assert.True(t, missing)
setting.Database.Type = "postgres"
missing, err = missingInstalledSQLiteDatabase()
require.NoError(t, err)
assert.False(t, missing)
}
func TestBuildAutoRecoveryConfigFromInstalledState(t *testing.T) {
adminUser, adminErr := user_model.GetAdminUser(context.Background())
recoveryCfg, err := buildAutoRecoveryConfigFromInstalledState(context.Background())
require.NoError(t, err)
if adminErr != nil {
require.True(t, user_model.IsErrUserNotExist(adminErr))
assert.Nil(t, recoveryCfg)
return
}
require.NotNil(t, adminUser)
if adminUser.Email == "" {
assert.Nil(t, recoveryCfg)
return
}
require.NotNil(t, recoveryCfg)
assert.True(t, recoveryCfg.Enabled)
assert.Equal(t, adminUser.Email, recoveryCfg.AllowedEmails)
assert.Equal(t, setting.Backup.Path, recoveryCfg.BackupPath)
assert.Equal(t, setting.RepoRootPath, recoveryCfg.RepoRootPath)
if setting.MailService != nil {
assert.Equal(t, setting.MailService.SMTPAddr, recoveryCfg.SMTPAddr)
assert.Equal(t, setting.MailService.SMTPPort, recoveryCfg.SMTPPort)
assert.Equal(t, setting.MailService.From, recoveryCfg.SMTPFrom)
assert.Equal(t, setting.MailService.User, recoveryCfg.SMTPUser)
assert.Equal(t, setting.MailService.Passwd, recoveryCfg.SMTPPasswd)
}
}
func TestShouldServeInstalledRecoveryWithMissingSQLite(t *testing.T) {
oldDatabase := setting.Database
oldInstallLock := setting.InstallLock
oldCustomConf := setting.CustomConf
defer func() {
setting.Database = oldDatabase
setting.InstallLock = oldInstallLock
setting.CustomConf = oldCustomConf
}()
tmpDir := t.TempDir()
setting.CustomConf = filepath.Join(tmpDir, "custom", "conf", "app.ini")
setting.Database.Type = "sqlite3"
setting.Database.Path = filepath.Join(tmpDir, "data", "gitea.db")
setting.InstallLock = true
require.NoError(t, os.MkdirAll(filepath.Dir(setting.InstallSentinelPath()), 0o755))
require.NoError(t, os.WriteFile(setting.InstallSentinelPath(), []byte("installed\n"), 0o600))
require.NoError(t, setting.SaveRecoveryConfig(&setting.RecoveryConfig{
Enabled: true,
AllowedEmails: "admin@example.com",
SMTPAddr: "smtp.example.com",
SMTPPort: "587",
SMTPFrom: "Gitea <noreply@example.com>",
}))
recoveryCfg, shouldServeRecovery, err := shouldServeInstalledRecovery(context.Background())
require.NoError(t, err)
require.True(t, shouldServeRecovery)
require.NotNil(t, recoveryCfg)
assert.Equal(t, "admin@example.com", recoveryCfg.AllowedEmails)
}
func TestRecoveryRequestBaseURLStripsRecoveryQueryFromAppURL(t *testing.T) {
// start edit/add - by petru @ codex
oldInstallLock := setting.InstallLock
oldAppURL := setting.AppURL
oldAppSubURL := setting.AppSubURL
defer func() {
setting.InstallLock = oldInstallLock
setting.AppURL = oldAppURL
setting.AppSubURL = oldAppSubURL
}()
setting.InstallLock = true
setting.AppURL = "http://example.com:3000/?recovery=1"
setting.AppSubURL = ""
req := httptest.NewRequest("GET", "http://example.com:3000/recovery", nil)
assert.Equal(t, "http://example.com:3000", recoveryRequestBaseURL(req))
// end edit/add - by petru @ codex
}
// end edit/add - by petru @ codex