Fresh repository history for elektrine/tarakan-client hosted at https://git.elektrine.com/elektrine/tarakan-client.
140 lines
4.3 KiB
Go
140 lines
4.3 KiB
Go
package snapshot
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCreatePinsCommitWithoutGitMetadataAndDetectsChanges(t *testing.T) {
|
|
repository := createTestRepository(t)
|
|
commit := gitOutput(t, repository, "rev-parse", "HEAD")
|
|
|
|
snapshot, err := Create(repository, commit)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := snapshot.Root
|
|
t.Cleanup(func() { _ = snapshot.Close() })
|
|
|
|
if _, err := os.Stat(filepath.Join(root, ".git")); !os.IsNotExist(err) {
|
|
t.Fatalf("snapshot retains Git metadata: %v", err)
|
|
}
|
|
changed, err := snapshot.Changed()
|
|
if err != nil || changed {
|
|
t.Fatalf("unchanged snapshot: changed=%v err=%v", changed, err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, "README.md"), []byte("changed\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
changed, err = snapshot.Changed()
|
|
if err != nil || !changed {
|
|
t.Fatalf("changed snapshot: changed=%v err=%v", changed, err)
|
|
}
|
|
|
|
if err := snapshot.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(root); !os.IsNotExist(err) {
|
|
t.Fatalf("snapshot was not destroyed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateRejectsUnavailableCommit(t *testing.T) {
|
|
repository := createTestRepository(t)
|
|
_, err := Create(repository, "dead000000000000000000000000000000000000")
|
|
if !errors.Is(err, ErrCommitUnavailable) {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateNeutralizesExternalAndEscapingSymlinks(t *testing.T) {
|
|
repository := createTestRepository(t)
|
|
|
|
// Absolute external pointer (common "works on my Mac" vendor path).
|
|
if err := os.Symlink("/Users/someone/Desktop/secret", filepath.Join(repository, "external-abs")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Relative path that escapes the tree.
|
|
if err := os.Symlink("../host-secret", filepath.Join(repository, "escape")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Safe in-tree relative link must be kept.
|
|
if err := os.Symlink("README.md", filepath.Join(repository, "readme-link")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runGitTest(t, repository, "add", "external-abs", "escape", "readme-link")
|
|
runGitTest(t, repository, "-c", "user.name=Tarakan Test", "-c", "user.email=test@tarakan.invalid", "commit", "-m", "symlinks")
|
|
|
|
commit := gitOutput(t, repository, "rev-parse", "HEAD")
|
|
snap, err := Create(repository, commit)
|
|
if err != nil {
|
|
t.Fatalf("Create should neutralize external symlinks, got: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = snap.Close() })
|
|
|
|
// Escaping / absolute links become ordinary files with the original target.
|
|
for _, name := range []string{"external-abs", "escape"} {
|
|
info, err := os.Lstat(filepath.Join(snap.Root, name))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode()&os.ModeSymlink != 0 {
|
|
t.Fatalf("%s still a symlink", name)
|
|
}
|
|
body, err := os.ReadFile(filepath.Join(snap.Root, name))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(body), "neutralized external symlink") {
|
|
t.Fatalf("%s body = %q", name, body)
|
|
}
|
|
}
|
|
|
|
// In-tree relative symlink preserved.
|
|
target, err := os.Readlink(filepath.Join(snap.Root, "readme-link"))
|
|
if err != nil {
|
|
t.Fatalf("safe symlink should remain: %v", err)
|
|
}
|
|
if target != "README.md" {
|
|
t.Fatalf("safe symlink target = %q", target)
|
|
}
|
|
|
|
changed, err := snap.Changed()
|
|
if err != nil || changed {
|
|
t.Fatalf("unchanged after neutralize: changed=%v err=%v", changed, err)
|
|
}
|
|
}
|
|
|
|
func createTestRepository(t *testing.T) string {
|
|
t.Helper()
|
|
repository := t.TempDir()
|
|
runGitTest(t, repository, "init", "-b", "main")
|
|
if err := os.WriteFile(filepath.Join(repository, "README.md"), []byte("pinned\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runGitTest(t, repository, "add", "README.md")
|
|
runGitTest(t, repository, "-c", "user.name=Tarakan Test", "-c", "user.email=test@tarakan.invalid", "commit", "-m", "initial")
|
|
return repository
|
|
}
|
|
|
|
func runGitTest(t *testing.T, directory string, arguments ...string) {
|
|
t.Helper()
|
|
command := exec.Command("git", append([]string{"-C", directory}, arguments...)...)
|
|
if output, err := command.CombinedOutput(); err != nil {
|
|
t.Fatalf("git %v: %v: %s", arguments, err, output)
|
|
}
|
|
}
|
|
|
|
func gitOutput(t *testing.T, directory string, arguments ...string) string {
|
|
t.Helper()
|
|
command := exec.Command("git", append([]string{"-C", directory}, arguments...)...)
|
|
output, err := command.Output()
|
|
if err != nil {
|
|
t.Fatalf("git %v: %v", arguments, err)
|
|
}
|
|
return strings.TrimSpace(string(output))
|
|
}
|