build(onboard): support codespace placeholder and path checks

This commit is contained in:
SiYue
2026-04-24 23:13:09 +08:00
parent e1863234f0
commit 494cc381b5
2 changed files with 79 additions and 3 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
)
//go:generate go run ../../../../scripts/copydir.go ../../../../workspace ./workspace
//go:generate go run ../../../../scripts/copydir.go "${DOLLAR}{codespace}/workspace" ./workspace
//go:embed workspace
var embeddedFiles embed.FS
+78 -2
View File
@@ -5,6 +5,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
)
func main() {
@@ -13,8 +14,36 @@ func main() {
os.Exit(2)
}
src := os.Args[1]
dst := os.Args[2]
repoRoot, err := findRepoRoot()
if err != nil {
fmt.Fprintf(os.Stderr, "locate repo root: %v\n", err)
os.Exit(1)
}
src, err := normalizePathArg(os.Args[1], repoRoot)
if err != nil {
fmt.Fprintf(os.Stderr, "resolve src path: %v\n", err)
os.Exit(1)
}
dst, err := normalizePathArg(os.Args[2], repoRoot)
if err != nil {
fmt.Fprintf(os.Stderr, "resolve dst path: %v\n", err)
os.Exit(1)
}
if err := ensurePathWithinRepo(repoRoot, src); err != nil {
fmt.Fprintf(os.Stderr, "invalid src path: %v\n", err)
os.Exit(1)
}
if err := ensurePathWithinRepo(repoRoot, dst); err != nil {
fmt.Fprintf(os.Stderr, "invalid dst path: %v\n", err)
os.Exit(1)
}
if samePath(repoRoot, dst) {
fmt.Fprintln(os.Stderr, "invalid dst path: destination cannot be repo root")
os.Exit(1)
}
if err := os.RemoveAll(dst); err != nil {
fmt.Fprintf(os.Stderr, "remove %s: %v\n", dst, err)
@@ -27,6 +56,53 @@ func main() {
}
}
func findRepoRoot() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
cur, err := filepath.Abs(wd)
if err != nil {
return "", err
}
for {
if _, err := os.Stat(filepath.Join(cur, ".git")); err == nil {
return filepath.Clean(cur), nil
}
parent := filepath.Dir(cur)
if parent == cur {
return "", fmt.Errorf("could not find .git from %s", wd)
}
cur = parent
}
}
func normalizePathArg(arg, repoRoot string) (string, error) {
resolved := strings.ReplaceAll(arg, "${codespace}", repoRoot)
abs, err := filepath.Abs(resolved)
if err != nil {
return "", err
}
return filepath.Clean(abs), nil
}
func ensurePathWithinRepo(repoRoot, path string) error {
rel, err := filepath.Rel(repoRoot, path)
if err != nil {
return err
}
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return fmt.Errorf("path %s is outside repository root %s", path, repoRoot)
}
return nil
}
func samePath(a, b string) bool {
return filepath.Clean(a) == filepath.Clean(b)
}
func copyTree(src, dst string) error {
info, err := os.Stat(src)
if err != nil {