Merge branch 'go-gitea:main' into main

This commit is contained in:
Karthik Bhandary
2026-02-25 13:34:27 +05:30
committed by GitHub
16 changed files with 343 additions and 95 deletions
+3 -1
View File
@@ -29,8 +29,10 @@ func TestShortSha(t *testing.T) {
func TestVerifyTimeLimitCode(t *testing.T) {
defer test.MockVariableValue(&setting.InstallLock, true)()
initGeneralSecret := func(secret string) {
setting.InstallLock = true
setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(`
[security]
INTERNAL_TOKEN = dummy
INSTALL_LOCK = true
[oauth2]
JWT_SECRET = %s
`, secret))
+9 -4
View File
@@ -7,6 +7,7 @@ import (
"context"
"fmt"
"os"
"strings"
"testing"
"time"
@@ -49,9 +50,11 @@ func TestRunWithContextStd(t *testing.T) {
stdout, stderr, err := cmd.RunStdString(t.Context())
if assert.Error(t, err) {
assert.Equal(t, stderr, err.Stderr())
assert.Equal(t, "fatal: Not a valid object name no-such\n", err.Stderr())
stderrLower := strings.ToLower(stderr) // see: IsStdErrorNotValidObjectName
assert.Equal(t, "fatal: not a valid object name no-such\n", stderrLower)
// FIXME: GIT-CMD-STDERR: it is a bad design, the stderr should not be put in the error message
assert.Equal(t, "exit status 128 - fatal: Not a valid object name no-such", err.Error())
errLower := strings.ToLower(err.Error())
assert.Equal(t, "exit status 128 - fatal: not a valid object name no-such", errLower)
assert.Empty(t, stdout)
}
}
@@ -61,9 +64,11 @@ func TestRunWithContextStd(t *testing.T) {
stdout, stderr, err := cmd.RunStdBytes(t.Context())
if assert.Error(t, err) {
assert.Equal(t, string(stderr), err.Stderr())
assert.Equal(t, "fatal: Not a valid object name no-such\n", err.Stderr())
stderrLower := strings.ToLower(err.Stderr()) // see: IsStdErrorNotValidObjectName
assert.Equal(t, "fatal: not a valid object name no-such\n", stderrLower)
// FIXME: GIT-CMD-STDERR: it is a bad design, the stderr should not be put in the error message
assert.Equal(t, "exit status 128 - fatal: Not a valid object name no-such", err.Error())
errLower := strings.ToLower(err.Error())
assert.Equal(t, "exit status 128 - fatal: not a valid object name no-such", errLower)
assert.Empty(t, stdout)
}
}
+7
View File
@@ -77,6 +77,13 @@ func IsErrorCanceledOrKilled(err error) bool {
return errors.Is(err, context.Canceled) || IsErrorSignalKilled(err)
}
func IsStdErrorNotValidObjectName(err error) bool {
stderr, ok := ErrorAsStderr(err)
// Git is lowercasing the "fatal: Not a valid object name" error message
// ref: https://lore.kernel.org/git/pull.2052.git.1771836302101.gitgitgadget@gmail.com
return ok && strings.Contains(strings.ToLower(stderr), "fatal: not a valid object name")
}
type pipelineError struct {
error
}
+1 -1
View File
@@ -65,7 +65,7 @@ func (t *Tree) ListEntries() (Entries, error) {
stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).WithDir(t.repo.Path).RunStdBytes(t.repo.Ctx)
if runErr != nil {
if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
if gitcmd.IsStdErrorNotValidObjectName(runErr) || strings.Contains(runErr.Error(), "fatal: not a tree object") {
return nil, ErrNotExist{
ID: t.ID.String(),
}
-1
View File
@@ -109,7 +109,6 @@ func generateSaveInternalToken(rootCfg ConfigProvider) {
func loadSecurityFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("security")
InstallLock = HasInstallLock(rootCfg)
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(31)
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
if SecretKey == "" {
+3
View File
@@ -108,6 +108,9 @@ func LoadCommonSettings() {
// loadCommonSettingsFrom loads common configurations from a configuration provider.
func loadCommonSettingsFrom(cfg ConfigProvider) error {
// a lot of logic depends on InstallLock value, so it must be loaded before any other settings
InstallLock = HasInstallLock(cfg)
// WARNING: don't change the sequence except you know what you are doing.
loadRunModeFrom(cfg)
loadLogGlobalFrom(cfg)
+69 -9
View File
@@ -64,7 +64,7 @@ func PathJoinRelX(elem ...string) string {
return PathJoinRel(elems...)
}
const pathSeparator = string(os.PathSeparator)
const filepathSeparator = string(os.PathSeparator)
// FilePathJoinAbs joins the path elements into a single file path, each element is cleaned by filepath.Clean separately.
// All slashes/backslashes are converted to path separators before cleaning, the result only contains path separators.
@@ -82,7 +82,7 @@ func FilePathJoinAbs(base string, sub ...string) string {
if isOSWindows() {
elems[0] = filepath.Clean(base)
} else {
elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator))
elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", filepathSeparator))
}
if !filepath.IsAbs(elems[0]) {
// This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead
@@ -93,9 +93,9 @@ func FilePathJoinAbs(base string, sub ...string) string {
continue
}
if isOSWindows() {
elems = append(elems, filepath.Clean(pathSeparator+s))
elems = append(elems, filepath.Clean(filepathSeparator+s))
} else {
elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator)))
elems = append(elems, filepath.Clean(filepathSeparator+strings.ReplaceAll(s, "\\", filepathSeparator)))
}
}
// the elems[0] must be an absolute path, just join them together
@@ -115,12 +115,72 @@ func IsDir(dir string) (bool, error) {
return false, err
}
func IsRegularFile(filePath string) (bool, error) {
f, err := os.Lstat(filePath)
if err == nil {
return f.Mode().IsRegular(), nil
var ErrNotRegularPathFile = errors.New("not a regular file")
// ReadRegularPathFile reads a file with given sub path in root dir.
// It returns error when the path is not a regular file, or any parent path is not a regular directory.
func ReadRegularPathFile(root, filePathIn string, limit int) ([]byte, error) {
pathFields := strings.Split(PathJoinRelX(filePathIn), "/")
targetPathBuilder := strings.Builder{}
targetPathBuilder.Grow(len(root) + len(filePathIn) + 2)
targetPathBuilder.WriteString(root)
targetPathString := root
for i, subPath := range pathFields {
targetPathBuilder.WriteByte(filepath.Separator)
targetPathBuilder.WriteString(subPath)
targetPathString = targetPathBuilder.String()
expectFile := i == len(pathFields)-1
st, err := os.Lstat(targetPathString)
if err != nil {
return nil, err
}
if expectFile && !st.Mode().IsRegular() || !expectFile && !st.Mode().IsDir() {
return nil, fmt.Errorf("%w: %s", ErrNotRegularPathFile, filePathIn)
}
}
return false, err
f, err := os.Open(targetPathString)
if err != nil {
return nil, err
}
defer f.Close()
return ReadWithLimit(f, limit)
}
// WriteRegularPathFile writes data to a file with given sub path in root dir, it creates parent directories if necessary.
// The file is created with fileMode, and the directories are created with dirMode.
// It returns error when the path already exists but is not a regular file, or any parent path is not a regular directory.
func WriteRegularPathFile(root, filePathIn string, data []byte, dirMode, fileMode os.FileMode) error {
pathFields := strings.Split(PathJoinRelX(filePathIn), "/")
targetPathBuilder := strings.Builder{}
targetPathBuilder.Grow(len(root) + len(filePathIn) + 2)
targetPathBuilder.WriteString(root)
targetPathString := root
for i, subPath := range pathFields {
targetPathBuilder.WriteByte(filepath.Separator)
targetPathBuilder.WriteString(subPath)
targetPathString = targetPathBuilder.String()
expectFile := i == len(pathFields)-1
st, err := os.Lstat(targetPathString)
if err == nil {
if expectFile && !st.Mode().IsRegular() || !expectFile && !st.Mode().IsDir() {
return fmt.Errorf("%w: %s", ErrNotRegularPathFile, filePathIn)
}
continue
}
if !os.IsNotExist(err) {
return err
}
if !expectFile {
if err = os.Mkdir(targetPathString, dirMode); err != nil {
return err
}
}
}
return os.WriteFile(targetPathString, data, fileMode)
}
// IsExist checks whether a file or directory exists.
+68
View File
@@ -6,6 +6,7 @@ package util
import (
"net/url"
"os"
"path/filepath"
"runtime"
"testing"
@@ -230,3 +231,70 @@ func TestListDirRecursively(t *testing.T) {
require.NoError(t, err)
assert.ElementsMatch(t, []string{"d1/f-d1", "d1/s1/f-d1s1"}, res)
}
func TestReadWriteRegularPathFile(t *testing.T) {
const readLimit = 10000
tmpDir := t.TempDir()
rootDir := tmpDir + "/root"
_ = os.Mkdir(rootDir, 0o755)
_ = os.WriteFile(tmpDir+"/other-file", []byte("other-content"), 0o755)
_ = os.Mkdir(rootDir+"/real-dir", 0o755)
_ = os.WriteFile(rootDir+"/real-dir/real-file", []byte("dummy-content"), 0o644)
_ = os.Symlink(rootDir+"/real-dir", rootDir+"/link-dir")
_ = os.Symlink(rootDir+"/real-dir/real-file", rootDir+"/real-dir/link-file")
t.Run("Read", func(t *testing.T) {
content, err := os.ReadFile(filepath.Join(rootDir, "../other-file"))
require.NoError(t, err)
assert.Equal(t, "other-content", string(content))
content, err = ReadRegularPathFile(rootDir, "../other-file", readLimit)
require.ErrorIs(t, err, os.ErrNotExist)
assert.Empty(t, string(content))
content, err = ReadRegularPathFile(rootDir, "real-dir/real-file", readLimit)
require.NoError(t, err)
assert.Equal(t, "dummy-content", string(content))
_, err = ReadRegularPathFile(rootDir, "link-dir/real-file", readLimit)
require.ErrorIs(t, err, ErrNotRegularPathFile)
_, err = ReadRegularPathFile(rootDir, "real-dir/link-file", readLimit)
require.ErrorIs(t, err, ErrNotRegularPathFile)
_, err = ReadRegularPathFile(rootDir, "link-dir/link-file", readLimit)
require.ErrorIs(t, err, ErrNotRegularPathFile)
})
t.Run("Write", func(t *testing.T) {
assertFileContent := func(path, expected string) {
data, err := os.ReadFile(path)
if expected == "" {
assert.ErrorIs(t, err, os.ErrNotExist)
return
}
require.NoError(t, err)
assert.Equal(t, expected, string(data), "file content mismatch for %s", path)
}
err := WriteRegularPathFile(rootDir, "new-dir/new-file", []byte("new-content"), 0o755, 0o644)
require.NoError(t, err)
assertFileContent(rootDir+"/new-dir/new-file", "new-content")
err = WriteRegularPathFile(rootDir, "link-dir/real-file", []byte("new-content"), 0o755, 0o644)
require.ErrorIs(t, err, ErrNotRegularPathFile)
err = WriteRegularPathFile(rootDir, "link-dir/link-file", []byte("new-content"), 0o755, 0o644)
require.ErrorIs(t, err, ErrNotRegularPathFile)
err = WriteRegularPathFile(rootDir, "link-dir/new-file", []byte("new-content"), 0o755, 0o644)
require.ErrorIs(t, err, ErrNotRegularPathFile)
err = WriteRegularPathFile(rootDir, "real-dir/link-file", []byte("new-content"), 0o755, 0o644)
require.ErrorIs(t, err, ErrNotRegularPathFile)
err = WriteRegularPathFile(rootDir, "../other-file", []byte("new-content"), 0o755, 0o644)
require.NoError(t, err)
assertFileContent(rootDir+"/../other-file", "other-content")
assertFileContent(rootDir+"/other-file", "new-content")
err = WriteRegularPathFile(rootDir, "real-dir/real-file", []byte("changed-content"), 0o755, 0o644)
require.NoError(t, err)
assertFileContent(rootDir+"/real-dir/real-file", "changed-content")
})
}