// SPDX-License-Identifier: AGPL-3.0-only // Command export-public-snapshot creates a host-neutral exact-file snapshot. package main import ( "bufio" "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "flag" "fmt" "os" "os/exec" "path/filepath" "sort" "strings" "time" ) const ( maxFileBytes = 1 << 20 maxTotalBytes = 16 << 20 maxFiles = 2000 ) type entry struct { Path string Mode os.FileMode Data []byte } type snapshot struct { SchemaVersion int `json:"schema_version"` Project string `json:"project"` ExportPolicy string `json:"export_policy"` FileCount int `json:"file_count"` AllowlistSHA256 string `json:"allowlist_sha256"` ManifestSHA256 string `json:"manifest_sha256"` } func main() { var source, destination string flag.StringVar(&source, "source", ".", "clean Git worktree root") flag.StringVar(&destination, "destination", "", "new destination directory") flag.Parse() if destination == "" || flag.NArg() != 0 { fatalf("usage: go run ./scripts/export-public-snapshot.go --destination PATH") } root := mustGit(source, "rev-parse", "--show-toplevel") root = mustReal(root) source = mustReal(source) if source != root { fatalf("--source must be the Git worktree root") } if strings.TrimSpace(mustGit(root, "status", "--porcelain=v1", "--untracked-files=all")) != "" { fatalf("release source worktree is dirty") } parent := mustReal(filepath.Dir(destination)) destination = filepath.Join(parent, filepath.Base(destination)) if filepath.Base(destination) == "." || filepath.Base(destination) == ".." { fatalf("invalid destination") } if _, err := os.Lstat(destination); !os.IsNotExist(err) { fatalf("destination already exists or cannot be inspected") } gitDir := mustReal(mustGit(root, "rev-parse", "--absolute-git-dir")) common := mustGit(root, "rev-parse", "--git-common-dir") if !filepath.IsAbs(common) { common = filepath.Join(root, common) } common = mustReal(common) for _, protected := range []string{root, gitDir, common} { if atOrBelow(parent, protected) { fatalf("destination must be outside the worktree and Git metadata") } } allowPath := "scripts/public-snapshot.allow" allow := mustGitBytes(root, "show", "HEAD:"+allowPath) paths := parseAllowlist(allow) entries := make([]entry, 0, len(paths)) total := 0 for _, path := range paths { line := mustGit(root, "ls-tree", "HEAD", "--", path) parts := strings.Fields(strings.SplitN(line, "\t", 2)[0]) if len(parts) != 3 || parts[1] != "blob" || (parts[0] != "100644" && parts[0] != "100755") || !strings.HasSuffix(line, "\t"+path) { fatalf("allowlisted path is absent or not a regular file: %s", path) } data := mustGitBytes(root, "show", "HEAD:"+path) if len(data) > maxFileBytes || bytes.IndexByte(data, 0) >= 0 { fatalf("allowlisted file is binary or oversized: %s", path) } if unsafeContent(data) { fatalf("private path, key, or credential indicator in: %s", path) } total += len(data) if total > maxTotalBytes { fatalf("snapshot exceeds aggregate size limit") } mode := os.FileMode(0o644) if parts[0] == "100755" { mode = 0o755 } entries = append(entries, entry{Path: path, Mode: mode, Data: data}) } stage, err := os.MkdirTemp(parent, ".sandwich-hime-tooling-public-") if err != nil { fatalf("create staging directory: %v", err) } owned := filepath.Join(stage, ".owned-public-export") if err := os.WriteFile(owned, []byte("owned staging directory\n"), 0o600); err != nil { fatalf("mark staging directory: %v", err) } defer func() { if _, err := os.Lstat(owned); err == nil { _ = os.RemoveAll(stage) } }() for _, item := range entries { target := filepath.Join(stage, filepath.FromSlash(item.Path)) if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { fatalf("create snapshot directory: %v", err) } if err := os.WriteFile(target, item.Data, item.Mode); err != nil { fatalf("write snapshot file: %v", err) } } manifest := buildManifest(entries) if err := os.WriteFile(filepath.Join(stage, "PUBLIC-SNAPSHOT.sha256"), manifest, 0o644); err != nil { fatalf("write manifest: %v", err) } allowSum := sha256.Sum256(allow) manifestSum := sha256.Sum256(manifest) metadata, err := json.Marshal(snapshot{ SchemaVersion: 1, Project: "sandwich-hime-tooling", ExportPolicy: "exact-allowlist-v1", FileCount: len(entries), AllowlistSHA256: hex.EncodeToString(allowSum[:]), ManifestSHA256: hex.EncodeToString(manifestSum[:]), }) if err != nil { fatalf("encode snapshot metadata: %v", err) } metadata = append(metadata, '\n') if err := os.WriteFile(filepath.Join(stage, "PUBLIC-SNAPSHOT.json"), metadata, 0o644); err != nil { fatalf("write snapshot metadata: %v", err) } _ = os.Remove(owned) epoch := time.Unix(0, 0) _ = filepath.Walk(stage, func(path string, info os.FileInfo, walkErr error) error { if walkErr == nil { _ = os.Chtimes(path, epoch, epoch) } return walkErr }) if err := os.Rename(stage, destination); err != nil { fatalf("activate snapshot: %v", err) } fmt.Printf("public snapshot: %d exact files written\n", len(entries)) } func parseAllowlist(data []byte) []string { seen := map[string]bool{} var paths []string scanner := bufio.NewScanner(bytes.NewReader(data)) for scanner.Scan() { path := scanner.Text() if path == "" || strings.HasPrefix(path, "#") { continue } clean := filepath.ToSlash(filepath.Clean(path)) lower := strings.ToLower(clean) if clean != path || filepath.IsAbs(path) || strings.ContainsAny(path, "\\\t\r\n") || strings.HasPrefix(path, "../") || path == ".." || seen[path] { fatalf("invalid or duplicate allowlist entry: %q", path) } for _, forbidden := range []string{"/.git/", "/.github/", "/.gitea/", "/private/", "/history/", "/node_modules/", "/dist/", "/artifacts/"} { if strings.Contains("/"+lower+"/", forbidden) { fatalf("forbidden allowlist entry: %s", path) } } seen[path] = true paths = append(paths, path) } if err := scanner.Err(); err != nil || len(paths) == 0 || len(paths) > maxFiles { fatalf("allowlist is empty, oversized, or unreadable") } sort.Strings(paths) return paths } func buildManifest(entries []entry) []byte { var out strings.Builder for _, item := range entries { sum := sha256.Sum256(item.Data) fmt.Fprintf(&out, "%x ./%s\n", sum, item.Path) } return []byte(out.String()) } func unsafeContent(data []byte) bool { lower := strings.ToLower(string(data)) begin := "-----begin " markers := []string{ begin + "private key-----", begin + "rsa private key-----", begin + "openssh private key-----", "/" + "home/" + "cole/", "c:\\" + "users\\" + "cole\\", "/mnt/c/" + "users/" + "cole/", "gh" + "p_", "gl" + "pat-", "xo" + "xb-", } for _, marker := range markers { if strings.Contains(lower, marker) { return true } } return false } func mustGit(root string, args ...string) string { return strings.TrimSpace(string(mustGitBytes(root, args...))) } func mustGitBytes(root string, args ...string) []byte { cmd := exec.Command("git", append([]string{"-C", root}, args...)...) output, err := cmd.Output() if err != nil { fatalf("git %s failed", strings.Join(args, " ")) } return output } func mustReal(path string) string { abs, err := filepath.Abs(path) if err != nil { fatalf("resolve path: %v", err) } real, err := filepath.EvalSymlinks(abs) if err != nil { fatalf("resolve path: %v", err) } return filepath.Clean(real) } func atOrBelow(path, root string) bool { rel, err := filepath.Rel(root, path) return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator)) } func fatalf(format string, args ...any) { fmt.Fprintf(os.Stderr, "public snapshot: "+format+"\n", args...) os.Exit(1) }