Home

git-age @main - refs - log - search -
https://git.jolheiser.com/git-age.git
git-crypt, but with age
cmd/cmd_test.go - raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
package cmd

import (
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/matryer/is"
)

const (
	ageIntro            = "age-encryption.org/v1"
	ageSecretContent    = "Super duper secret age text!"
	sshSecretContent    = "Super duper secret ssh text!"
	newAgeSecretContent = "Super duper secret age text!!"
)

func TestGitAge(t *testing.T) {
	assert := is.New(t)

	gitDir, err := gitBaseDir()
	assert.NoErr(err) // Should get git base dir
	tmp := t.TempDir()
	clone := exec.Command("git", "clone", gitDir, tmp)
	clone.Dir = tmp
	assert.NoErr(clone.Run()) // Should clone project to temp dir

	ageSecretPath := filepath.Join(tmp, "secrets", "age.txt")
	assertEncrypted(assert, ageSecretPath) // Age secret should be encrypted before init
	sshSecretPath := filepath.Join(tmp, "secrets", "ssh.txt")
	assertEncrypted(assert, sshSecretPath) // SSH secret should be encrypted before init

	err = os.Chdir(tmp)
	assert.NoErr(err) // Should change to temp dir
	build := exec.Command("go", "build")
	build.Dir = tmp
	err = build.Run()
	assert.NoErr(err) // Should build git-age
	binPath := filepath.Join(tmp, "git-age")
	if runtime.GOOS == "windows" {
		binPath += ".exe"
	}
	bin := func(args ...string) error {
		c := exec.Command(binPath, args...)
		c.Dir = tmp
		return c.Run()
	}
	assertGitCatFileEncrypted(assert) // cat-file should always be encrypted (initial clone)

	// Init should do nothing at first
	err = bin("init")
	assert.NoErr(err)                      // Should successfully run init
	assertEncrypted(assert, ageSecretPath) // Age secret should be encrypted on init without identities
	assertEncrypted(assert, sshSecretPath) // SSH secret should be encrypted on init without identities

	// Add identities
	err = bin("ident", "key.txt")
	assert.NoErr(err) // Should add age identity
	err = bin("ident", "ssh")
	assert.NoErr(err) // Should add ssh identity

	// Init should work now
	err = bin("init")
	assert.NoErr(err) // Should successfully run init
	ageContent, err := os.ReadFile(ageSecretPath)
	assert.NoErr(err)                                   // Should read age secret file
	assert.True(string(ageContent) == ageSecretContent) // Age secret content should match constant
	sshContent, err := os.ReadFile(sshSecretPath)
	assert.NoErr(err)                                   // Should read ssh secret file
	assert.True(string(sshContent) == sshSecretContent) // SSH secret content should match constant
	assertGitCatFileEncrypted(assert)                   // cat-file should always be encrypted (after git-age init)

	err = os.WriteFile(ageSecretPath, []byte(newAgeSecretContent), os.ModePerm)
	assert.NoErr(err) // Should be able to write the file

	git := func(args ...string) error {
		args = append([]string{"-c", "user.name=foo", "-c", "user.email=baz@bar.bux", "-c", "commit.gpgsign=false"}, args...)
		c := exec.Command("git", args...)
		c.Dir = tmp
		return c.Run()
	}

	err = git("add", ageSecretPath)
	assert.NoErr(err) // Git add should succeed
	err = git("commit", "-m", "feat!: YOLO")
	assert.NoErr(err) // Commit should succeed

	assertGitCatFileEncrypted(assert) // cat-file should always be encrypted (after commit)
}

func assertGitCatFileEncrypted(t *is.I) {
	t.Helper()

	out, err := exec.Command("git", "cat-file", "blob", "HEAD:secrets/age.txt").Output()
	t.NoErr(err)
	t.True(strings.HasPrefix(string(out), ageIntro))
}

func assertEncrypted(t *is.I, fp string) {
	t.Helper()

	content, err := os.ReadFile(fp)
	t.NoErr(err)

	t.True(strings.HasPrefix(string(content), ageIntro))
}