Fix path resolving (#36734)

This commit is contained in:
wxiaoguang
2026-02-25 09:21:07 +08:00
committed by GitHub
parent d19d4da5ce
commit 2176e84ab9
4 changed files with 228 additions and 79 deletions
+37 -45
View File
@@ -103,12 +103,12 @@ func generateExpansion(ctx context.Context, src string, templateRepo, generateRe
// giteaTemplateFileMatcher holds information about a .gitea/template file
type giteaTemplateFileMatcher struct {
LocalFullPath string
globs []glob.Glob
relPath string
globs []glob.Glob
}
func newGiteaTemplateFileMatcher(fullPath string, content []byte) *giteaTemplateFileMatcher {
gt := &giteaTemplateFileMatcher{LocalFullPath: fullPath}
func newGiteaTemplateFileMatcher(relPath string, content []byte) *giteaTemplateFileMatcher {
gt := &giteaTemplateFileMatcher{relPath: relPath}
gt.globs = make([]glob.Glob, 0)
scanner := bufio.NewScanner(bytes.NewReader(content))
for scanner.Scan() {
@@ -139,64 +139,44 @@ func (gt *giteaTemplateFileMatcher) Match(s string) bool {
return false
}
func readLocalTmpRepoFileContent(localPath string, limit int) ([]byte, error) {
ok, err := util.IsRegularFile(localPath)
if err != nil {
return nil, err
} else if !ok {
return nil, fs.ErrNotExist
}
f, err := os.Open(localPath)
if err != nil {
return nil, err
}
defer f.Close()
return util.ReadWithLimit(f, limit)
}
func readGiteaTemplateFile(tmpDir string) (*giteaTemplateFileMatcher, error) {
localPath := filepath.Join(tmpDir, ".gitea", "template")
content, err := readLocalTmpRepoFileContent(localPath, 1024*1024)
templateRelPath := filepath.Join(".gitea", "template")
content, err := util.ReadRegularPathFile(tmpDir, templateRelPath, 1024*1024)
if err != nil {
return nil, err
return nil, util.Iif(errors.Is(err, util.ErrNotRegularPathFile), os.ErrNotExist, err)
}
return newGiteaTemplateFileMatcher(localPath, content), nil
return newGiteaTemplateFileMatcher(templateRelPath, content), nil
}
func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, templateRepo, generateRepo *repo_model.Repository) error {
tmpFullPath := filepath.Join(tmpDir, tmpDirSubPath)
content, err := readLocalTmpRepoFileContent(tmpFullPath, 1024*1024)
content, err := util.ReadRegularPathFile(tmpDir, tmpDirSubPath, 1024*1024)
if err != nil {
return util.Iif(errors.Is(err, fs.ErrNotExist), nil, err)
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return err
}
if err := util.Remove(tmpFullPath); err != nil {
if err := os.Remove(util.FilePathJoinAbs(tmpDir, tmpDirSubPath)); err != nil {
return err
}
generatedContent := generateExpansion(ctx, string(content), templateRepo, generateRepo)
substSubPath := filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo))
newLocalPath := filepath.Join(tmpDir, substSubPath)
regular, err := util.IsRegularFile(newLocalPath)
if canWrite := regular || errors.Is(err, fs.ErrNotExist); !canWrite {
return nil
}
if err := os.MkdirAll(filepath.Dir(newLocalPath), 0o755); err != nil {
return err
}
return os.WriteFile(newLocalPath, []byte(generatedContent), 0o644)
return util.WriteRegularPathFile(tmpDir, substSubPath, []byte(generatedContent), 0o755, 0o644)
}
func processGiteaTemplateFile(ctx context.Context, tmpDir string, templateRepo, generateRepo *repo_model.Repository, fileMatcher *giteaTemplateFileMatcher) error {
if err := util.Remove(fileMatcher.LocalFullPath); err != nil {
return fmt.Errorf("unable to remove .gitea/template: %w", err)
// processGiteaTemplateFile processes and removes the .gitea/template file, does variable expansion for template files
// and save the processed files to the filesystem. It returns a list of skipped files that are not regular paths.
func processGiteaTemplateFile(ctx context.Context, tmpDir string, templateRepo, generateRepo *repo_model.Repository, fileMatcher *giteaTemplateFileMatcher) (skippedFiles []string, _ error) {
// Why not use "os.Root" here: symlink is unsafe even in the same root but "os.Root" can't help, it's more difficult to use "os.Root" to do the WalkDir.
if err := os.Remove(util.FilePathJoinAbs(tmpDir, fileMatcher.relPath)); err != nil {
return nil, fmt.Errorf("unable to remove .gitea/template: %w", err)
}
if !fileMatcher.HasRules() {
return nil // Avoid walking tree if there are no globs
return skippedFiles, nil // Avoid walking tree if there are no globs
}
return filepath.WalkDir(tmpDir, func(fullPath string, d os.DirEntry, walkErr error) error {
err := filepath.WalkDir(tmpDir, func(fullPath string, d os.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
@@ -208,10 +188,22 @@ func processGiteaTemplateFile(ctx context.Context, tmpDir string, templateRepo,
return err
}
if fileMatcher.Match(filepath.ToSlash(tmpDirSubPath)) {
return substGiteaTemplateFile(ctx, tmpDir, tmpDirSubPath, templateRepo, generateRepo)
err := substGiteaTemplateFile(ctx, tmpDir, tmpDirSubPath, templateRepo, generateRepo)
if errors.Is(err, util.ErrNotRegularPathFile) {
skippedFiles = append(skippedFiles, tmpDirSubPath)
} else if err != nil {
return err
}
}
return nil
}) // end: WalkDir
if err != nil {
return nil, err
}
if err = util.RemoveAll(util.FilePathJoinAbs(tmpDir, ".git")); err != nil {
return nil, err
}
return skippedFiles, nil
}
func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error {
@@ -236,7 +228,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
// Variable expansion
fileMatcher, err := readGiteaTemplateFile(tmpDir)
if err == nil {
err = processGiteaTemplateFile(ctx, tmpDir, templateRepo, generateRepo, fileMatcher)
_, err = processGiteaTemplateFile(ctx, tmpDir, templateRepo, generateRepo, fileMatcher)
if err != nil {
return fmt.Errorf("processGiteaTemplateFile: %w", err)
}