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)) }