From 274986ad9c5f05e7333fdb8aefb1717ab3029fdb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 29 Aug 2018 18:39:50 -0400 Subject: [PATCH] Optionally, authorship and approval information appended to policies (#54) --- example/comply.yml.example | 12 +++++++++++ internal/config/config.go | 1 + internal/render/document.go | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/example/comply.yml.example b/example/comply.yml.example index e037a62..a18df72 100644 --- a/example/comply.yml.example +++ b/example/comply.yml.example @@ -1,5 +1,17 @@ name: "Acme" filePrefix: "Acme" + +# The following setting is optional. +# If you set this (to, e.g. master), and you build the policies +# on that branch, then a section is appended to each policy that +# describes the approval. Text will look like: +# +# Last edit made by John Doe (jdoe@email.com) on Wed, 15 Aug 2018 12:45:28 -0400. +# Approved by Joan Smith (jsmith@email.com) on Wed, 15 Aug 2018 16:54:48 -0400 in commit abc123123. +# +# The change author gets credit for the edit. +# The person who committed or merged to the approval branch gets credit for approval. +approvedBranch: master tickets: github: token: XXX diff --git a/internal/config/config.go b/internal/config/config.go index 99ba597..66b0380 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -37,6 +37,7 @@ type Project struct { Pandoc string `yaml:"pandoc,omitempty"` FilePrefix string `yaml:"filePrefix"` Tickets map[string]interface{} `yaml:"tickets"` + ApprovedBranch string `yaml:"approvedBranch"` } // SetPandoc records pandoc availability during initialization diff --git a/internal/render/document.go b/internal/render/document.go index da5fe40..04c62e7 100644 --- a/internal/render/document.go +++ b/internal/render/document.go @@ -14,6 +14,7 @@ import ( "github.com/pkg/errors" "github.com/strongdm/comply/internal/config" "github.com/strongdm/comply/internal/model" + "os/exec" ) // TODO: refactor and eliminate duplication among narrative, policy renderers @@ -53,6 +54,36 @@ func renderToFilesystem(wg *sync.WaitGroup, errOutputCh chan error, data *render }(doc) } +func getGitApprovalInfo(pol *model.Document) (string, error) { + cfg := config.Config() + + // Decide whether we are on the git branch that contains the approved policies + gitBranchArgs := []string{"rev-parse","--abbrev-ref", "HEAD"} + gitBranchCmd := exec.Command("git", gitBranchArgs...) + gitBranchInfo, err := gitBranchCmd.CombinedOutput() + if err != nil { + fmt.Println(string(gitBranchInfo)) + return "", errors.Wrap(err, "error looking up git branch") + } + + // if no approved branch specified in config.yaml, then nothing gets added to the document + // if on a different branch than the approved branch, then nothing gets added to the document + if len(cfg.ApprovedBranch) == 0 || strings.Compare(strings.TrimSpace(fmt.Sprintf("%s",gitBranchInfo)), cfg.ApprovedBranch ) != 0 { + return "", nil + } + + // Grab information related to commit, so that we can put approval information in the document + gitArgs := []string{"log", "-n", "1", "--pretty=format:Last edit made by %an (%aE) on %aD.\n\nApproved by %cn (%cE) on %cD in commit %H.", "--", pol.FullPath} + cmd := exec.Command("git", gitArgs...) + gitApprovalInfo, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(string(gitApprovalInfo)) + return "", errors.Wrap(err, "error looking up git committer and author data") + } + + return fmt.Sprintf("%s\n%s", "# Authorship and Approval", gitApprovalInfo), nil +} + func preprocessDoc(data *renderData, pol *model.Document, fullPath string) error { cfg := config.Config() @@ -89,6 +120,12 @@ func preprocessDoc(data *renderData, pol *model.Document, fullPath string) error revisionTable = fmt.Sprintf("|Date|Comment|\n|---+--------------------------------------------|\n%s\nTable: Document history\n", rows) } + gitApprovalInfo, err := getGitApprovalInfo(pol) + if err != nil { + return err + } + + doc := fmt.Sprintf(`%% %s %% %s %% %s @@ -104,6 +141,8 @@ foot-content: "%s confidential %d" %s \newpage +%s + %s`, pol.Name, cfg.Name, @@ -114,6 +153,7 @@ foot-content: "%s confidential %d" satisfiesTable, revisionTable, body, + gitApprovalInfo, ) err = ioutil.WriteFile(fullPath, []byte(doc), os.FileMode(0644)) if err != nil {