Initial commit on Forgejo
Some checks failed
CI and releases / Test and vet (push) Failing after 1s
CI and releases / Build release binaries (push) Has been skipped
CI and releases / Publish GitHub release (push) Has been skipped

Fresh repository history for elektrine/tarakan-client hosted at
https://git.elektrine.com/elektrine/tarakan-client.
This commit is contained in:
Maxfield Luke 2026-07-29 04:56:36 -04:00
commit 58b29a7f84
70 changed files with 12994 additions and 0 deletions

View file

@ -0,0 +1,240 @@
package snapshot
import (
"crypto/sha256"
"errors"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
var (
ErrCommitUnavailable = errors.New("pinned commit is not available in the local repository")
fullCommitPattern = regexp.MustCompile(`^[0-9a-fA-F]{40}$`)
)
// Snapshot is a disposable, metadata-free copy of one exact Git commit.
type Snapshot struct {
Root string
base string
baseline [sha256.Size]byte
}
// Create materializes commit from repositoryRoot without sharing Git object
// hardlinks. Hooks, global Git configuration, and interactive credential
// prompts are disabled for every Git subprocess involved in the snapshot.
func Create(repositoryRoot, commit string) (*Snapshot, error) {
if !fullCommitPattern.MatchString(commit) {
return nil, errors.New("task commit must be a full 40-character hexadecimal SHA")
}
if err := gitAvailable(repositoryRoot, commit); err != nil {
return nil, err
}
base, err := os.MkdirTemp("", "tarakan-snapshot-")
if err != nil {
return nil, fmt.Errorf("create snapshot directory: %w", err)
}
cleanup := true
defer func() {
if cleanup {
_ = os.RemoveAll(base)
}
}()
home := filepath.Join(base, "home")
if err := os.Mkdir(home, 0o700); err != nil {
return nil, fmt.Errorf("create isolated Git home: %w", err)
}
root := filepath.Join(base, "repository")
if output, err := runGit(base, home, "-c", "core.hooksPath=/dev/null", "clone", "--local", "--no-hardlinks", "--no-checkout", "--", repositoryRoot, root); err != nil {
return nil, fmt.Errorf("clone repository snapshot: %w: %s", err, strings.TrimSpace(output))
}
if output, err := runGit(base, home,
"-C", root,
"-c", "core.hooksPath=/dev/null",
"-c", "filter.lfs.smudge=",
"-c", "filter.lfs.required=false",
"checkout", "--detach", "--force", commit,
); err != nil {
return nil, fmt.Errorf("check out pinned commit: %w: %s", err, strings.TrimSpace(output))
}
// Absolute or escaping symlinks would let the agent read host paths.
// Neutralize them (replace with a small text file) instead of failing:
// many real repos ship broken absolute "external/" pointers from another
// machine (e.g. /Users/... on Linux), and the review should still run.
if err := neutralizeExternalSymlinks(root); err != nil {
return nil, err
}
if err := os.RemoveAll(filepath.Join(root, ".git")); err != nil {
return nil, fmt.Errorf("remove snapshot Git metadata: %w", err)
}
baseline, err := digestTree(root)
if err != nil {
return nil, fmt.Errorf("hash repository snapshot: %w", err)
}
cleanup = false
return &Snapshot{Root: root, base: base, baseline: baseline}, nil
}
func neutralizeExternalSymlinks(root string) error {
return filepath.WalkDir(root, func(path string, entry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if entry.Type()&os.ModeSymlink == 0 {
return nil
}
target, err := os.Readlink(path)
if err != nil {
return err
}
if !isExternalSymlink(root, path, target) {
return nil
}
rel, relErr := filepath.Rel(root, path)
if relErr != nil {
rel = path
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("remove external symlink %s: %w", filepath.ToSlash(rel), err)
}
// Regular file: agent cannot follow it to host content; original
// target is preserved as text so reviewers still see the pointer.
body := "tarakan-snapshot: neutralized external symlink\noriginal-target: " + target + "\n"
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
return fmt.Errorf("neutralize external symlink %s: %w", filepath.ToSlash(rel), err)
}
return nil
})
}
// isExternalSymlink is true for absolute targets or relative targets that
// resolve outside the snapshot root.
func isExternalSymlink(root, path, target string) bool {
if filepath.IsAbs(target) {
return true
}
resolved := filepath.Clean(filepath.Join(filepath.Dir(path), target))
relative, err := filepath.Rel(root, resolved)
if err != nil || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
return true
}
return false
}
// Changed reports whether any path, mode, symlink target, or regular-file
// content differs from the snapshot presented to the agent.
func (s *Snapshot) Changed() (bool, error) {
current, err := digestTree(s.Root)
if err != nil {
return false, err
}
return current != s.baseline, nil
}
// Close destroys the snapshot. It is safe to call more than once.
func (s *Snapshot) Close() error {
if s == nil || s.base == "" {
return nil
}
base := s.base
s.base = ""
return os.RemoveAll(base)
}
func gitAvailable(repositoryRoot, commit string) error {
command := exec.Command("git", "-C", repositoryRoot, "cat-file", "-e", commit+"^{commit}")
command.Env = gitEnvironment(os.TempDir())
if err := command.Run(); err != nil {
return fmt.Errorf("%w: %s (run git fetch origin first)", ErrCommitUnavailable, commit)
}
return nil
}
func runGit(directory, home string, arguments ...string) (string, error) {
command := exec.Command("git", arguments...)
command.Dir = directory
command.Env = gitEnvironment(home)
output, err := command.CombinedOutput()
return string(output), err
}
func gitEnvironment(home string) []string {
filtered := make([]string, 0, len(os.Environ())+6)
for _, entry := range os.Environ() {
name, _, _ := strings.Cut(entry, "=")
switch strings.ToUpper(name) {
case "HOME", "XDG_CONFIG_HOME", "GIT_CONFIG_GLOBAL", "GIT_CONFIG_SYSTEM", "GIT_CONFIG_NOSYSTEM", "GIT_TERMINAL_PROMPT", "GIT_ASKPASS", "SSH_ASKPASS":
continue
}
if strings.HasPrefix(strings.ToUpper(name), "TARAKAN_") {
continue
}
filtered = append(filtered, entry)
}
return append(filtered,
"HOME="+home,
"XDG_CONFIG_HOME="+filepath.Join(home, ".config"),
"GIT_CONFIG_NOSYSTEM=1",
"GIT_CONFIG_GLOBAL=/dev/null",
"GIT_TERMINAL_PROMPT=0",
)
}
func digestTree(root string) ([sha256.Size]byte, error) {
hash := sha256.New()
err := filepath.WalkDir(root, func(path string, entry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
relative, err := filepath.Rel(root, path)
if err != nil {
return err
}
info, err := entry.Info()
if err != nil {
return err
}
_, _ = io.WriteString(hash, filepath.ToSlash(relative))
_, _ = io.WriteString(hash, "\x00"+info.Mode().String()+"\x00")
switch {
case info.Mode()&os.ModeSymlink != 0:
target, err := os.Readlink(path)
if err != nil {
return err
}
_, _ = io.WriteString(hash, target)
case info.Mode().IsRegular():
file, err := os.Open(path)
if err != nil {
return err
}
_, copyErr := io.Copy(hash, file)
closeErr := file.Close()
if copyErr != nil {
return copyErr
}
if closeErr != nil {
return closeErr
}
}
_, _ = io.WriteString(hash, "\x00")
return nil
})
if err != nil {
return [sha256.Size]byte{}, err
}
var result [sha256.Size]byte
copy(result[:], hash.Sum(nil))
return result, nil
}