diff --git a/README.md b/README.md index a5bafb5..3f7d3ab 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ This project gives developers the ability to describe and check the architecture of a project and check it is respected at any time. +## TODO + +- add docs to tell what options each expression support (even better: enforce that using type system) + ## Desired usecases if a folder: @@ -25,7 +29,7 @@ if a file: - [ ] content matches template - [x] content contains a value - [x] is gitignored -- [ ] is gitcrypted +- [x] is gitcrypted - [ ] has specific permissions if a set of files: diff --git a/internal/arch/file/should/be_gitencrypted.go b/internal/arch/file/should/be_gitencrypted.go new file mode 100644 index 0000000..a6570c7 --- /dev/null +++ b/internal/arch/file/should/be_gitencrypted.go @@ -0,0 +1,49 @@ +package should + +import ( + "bytes" + "fmt" + "goarkitect/internal/arch/rule" + "os/exec" + "path/filepath" +) + +func BeGitencrypted(opts ...Option) *gitEncryptedExpression { + expr := &gitEncryptedExpression{} + + for _, opt := range opts { + opt.apply(&expr.options) + } + + return expr +} + +type gitEncryptedExpression struct { + baseExpression +} + +func (e gitEncryptedExpression) Evaluate(rb rule.Builder) []rule.Violation { + return e.evaluate(rb, e.doEvaluate, e.getViolation) +} + +func (e gitEncryptedExpression) doEvaluate(rb rule.Builder, filePath string) bool { + cmd := exec.Command("git", "crypt", "status", filePath) + out, err := cmd.CombinedOutput() + if err != nil { + panic(err) + } + + return bytes.Contains(out, []byte("not encrypted")) +} + +func (e gitEncryptedExpression) getViolation(filePath string) rule.Violation { + format := "file '%s' is not gitencrypted" + + if e.options.negated { + format = "file '%s' is gitencrypted" + } + + return rule.NewViolation( + fmt.Sprintf(format, filepath.Base(filePath)), + ) +} diff --git a/internal/arch/file/should/be_gitencrypted_test.go b/internal/arch/file/should/be_gitencrypted_test.go new file mode 100644 index 0000000..3dc41da --- /dev/null +++ b/internal/arch/file/should/be_gitencrypted_test.go @@ -0,0 +1,69 @@ +package should_test + +import ( + "goarkitect/internal/arch/file" + "goarkitect/internal/arch/file/should" + "goarkitect/internal/arch/rule" + "os" + "path/filepath" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +func Test_BeGitencrypted(t *testing.T) { + basePath, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + desc string + ruleBuilder *file.RuleBuilder + options []should.Option + want []rule.Violation + }{ + { + desc: "file 'encrypted.txt' should be gitencrypted", + ruleBuilder: file.One(filepath.Join(basePath, "test/encrypted.txt")), + want: nil, + }, + { + desc: "file 'not_encrypted.txt' should be gitencrypted", + ruleBuilder: file.One(filepath.Join(basePath, "test/not_encrypted.txt")), + want: []rule.Violation{ + rule.NewViolation("file 'not_encrypted.txt' is not gitencrypted"), + }, + }, + { + desc: "negated: file 'encrypted.txt' should not be gitencrypted", + ruleBuilder: file.One(filepath.Join(basePath, "test/encrypted.txt")), + options: []should.Option{ + should.Negated{}, + }, + want: []rule.Violation{ + rule.NewViolation("file 'encrypted.txt' is gitencrypted"), + }, + }, + { + desc: "negated: file 'not_encrypted.txt' should not be gitencrypted", + ruleBuilder: file.One(filepath.Join(basePath, "test/not_encrypted.txt")), + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, + } + + for _, tC := range testCases { + t.Run(tC.desc, func(t *testing.T) { + hcm := should.BeGitencrypted(tC.options...) + got := hcm.Evaluate(tC.ruleBuilder) + + if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { + t.Errorf("want = %+v, got = %+v", tC.want, got) + } + }) + } +} diff --git a/internal/arch/file/should/test/.gitattributes b/internal/arch/file/should/test/.gitattributes new file mode 100644 index 0000000..194987e --- /dev/null +++ b/internal/arch/file/should/test/.gitattributes @@ -0,0 +1 @@ +encrypted.txt filter=git-crypt diff=git-crypt diff --git a/internal/arch/file/should/test/encrypted.txt b/internal/arch/file/should/test/encrypted.txt new file mode 100644 index 0000000..a1321d2 Binary files /dev/null and b/internal/arch/file/should/test/encrypted.txt differ diff --git a/internal/arch/file/should/test/not_encrypted.txt b/internal/arch/file/should/test/not_encrypted.txt new file mode 100644 index 0000000..54cd4f8 --- /dev/null +++ b/internal/arch/file/should/test/not_encrypted.txt @@ -0,0 +1 @@ +I am not encrypted