Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/core/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ type Provider interface {

type Checker interface {
CheckAccessPolicy(ciService ci.OrgService, SCMOrganisation string, SCMrepository string, projectname string, command string, requestedBy string) (bool, error)
CheckPlanPolicy(SCMrepository string, projectname string, planOutput string) (bool, error)
CheckPlanPolicy(SCMrepository string, projectname string, planOutput string) (bool, []string, error)
}
14 changes: 10 additions & 4 deletions pkg/digger/digger.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,19 +171,24 @@ func RunCommandsPerProject(
if err != nil {
log.Printf("Failed to report plan. %v", err)
}
planIsAllowed, err := policyChecker.CheckPlanPolicy(SCMrepository, projectCommands.ProjectName, planJsonOutput)
planIsAllowed, messages, err := policyChecker.CheckPlanPolicy(SCMrepository, projectCommands.ProjectName, planJsonOutput)
if err != nil {
log.Printf("failed to validate plan %v", err)
return false, false, fmt.Errorf("failed to validated plan %v", err)
}
planPolicyFormatter := utils.AsCollapsibleComment(fmt.Sprintf("Terraform plan validation check (%v)", projectCommands.ProjectName))
if !planIsAllowed {
formatter := utils.AsCollapsibleComment("Terraform plan failed validation checks")
err = reporter.Report("Terraform plan failed validation checks", formatter)
planReportMessage := "Terraform plan failed validation checks :x:\n"
planReportMessage = planReportMessage + " " + strings.Join(messages, " \n")
err = reporter.Report(planReportMessage, planPolicyFormatter)

if err != nil {
log.Printf("Failed to report plan. %v", err)
}
log.Printf("Plan is not allowed")
return false, false, fmt.Errorf("Plan is not allowed")
} else {
reporter.Report("Terraform plan validation checks succeeded :white_check_mark:", planPolicyFormatter)
}
}
err := prService.SetStatus(prNumber, "success", projectCommands.ProjectName+"/plan")
Expand Down Expand Up @@ -352,7 +357,8 @@ func RunCommandForProject(
log.Printf("Failed to run digger plan command. %v", err)
return fmt.Errorf("failed to run digger plan command. %v", err)
}
planIsAllowed, err := policyChecker.CheckPlanPolicy(SCMrepository, commands.ProjectName, planJsonOutput)
planIsAllowed, messages, err := policyChecker.CheckPlanPolicy(SCMrepository, commands.ProjectName, planJsonOutput)
fmt.Printf(strings.Join(messages, "\n"))
if err != nil {
log.Printf("failed to validate plan %v", err)
return fmt.Errorf("failed to validated plan %v", err)
Expand Down
31 changes: 20 additions & 11 deletions pkg/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func (p NoOpPolicyChecker) CheckAccessPolicy(_ ci.OrgService, _ string, _ string
return true, nil
}

func (p NoOpPolicyChecker) CheckPlanPolicy(_ string, _ string, _ string) (bool, error) {
return true, nil
func (p NoOpPolicyChecker) CheckPlanPolicy(_ string, _ string, _ string) (bool, []string, error) {
return true, nil, nil
}

func getAccessPolicyForOrganisation(p *DiggerHttpPolicyProvider) (string, *http.Response, error) {
Expand Down Expand Up @@ -267,25 +267,26 @@ func (p DiggerPolicyChecker) CheckAccessPolicy(ciService ci.OrgService, SCMOrgan
return true, nil
}

func (p DiggerPolicyChecker) CheckPlanPolicy(SCMrepository string, projectName string, planOutput string) (bool, error) {
func (p DiggerPolicyChecker) CheckPlanPolicy(SCMrepository string, projectName string, planOutput string) (bool, []string, error) {
// TODO: Get rid of organisation if its not needed
organisation := p.PolicyProvider.GetOrganisation()
policy, err := p.PolicyProvider.GetPlanPolicy(organisation, SCMrepository, projectName)
if err != nil {
return false, fmt.Errorf("failed get plan policy: %v", err)
return false, nil, fmt.Errorf("failed get plan policy: %v", err)
}
var parsedPlanOutput map[string]interface{}
err = json.Unmarshal([]byte(planOutput), &parsedPlanOutput)
if err != nil {
return false, fmt.Errorf("failed to parse json terraform output to map: %v", err)
return false, nil, fmt.Errorf("failed to parse json terraform output to map: %v", err)
}

input := map[string]interface{}{
"terraform": parsedPlanOutput,
}

if policy == "" {
return true, nil
fmt.Printf("No plan policies found, succeeding")
return true, nil, nil
}

ctx := context.Background()
Expand All @@ -296,28 +297,36 @@ func (p DiggerPolicyChecker) CheckPlanPolicy(SCMrepository string, projectName s
).PrepareForEval(ctx)

if err != nil {
return false, err
return false, nil, err
}

results, err := query.Eval(ctx, rego.EvalInput(input))
if len(results) == 0 || len(results[0].Expressions) == 0 {
return false, fmt.Errorf("no result found")
return false, nil, fmt.Errorf("no result found")
}

expressions := results[0].Expressions

decisionsResult := make([]string, 0)
for _, expression := range expressions {
decisions, ok := expression.Value.([]interface{})

if !ok {
return false, fmt.Errorf("decision is not a slice of interfaces")
return false, nil, fmt.Errorf("decision is not a slice of interfaces")
}
if len(decisions) > 0 {
for _, d := range decisions {
decisionsResult = append(decisionsResult, d.(string))
fmt.Printf("denied: %v\n", d)
}
return false, nil

}

}

return true, nil
if len(decisionsResult) > 0 {
return false, decisionsResult, nil
}

return true, []string{}, nil
}
2 changes: 1 addition & 1 deletion pkg/policy/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func TestDiggerPlanPolicyChecker_Check(t *testing.T) {
var p = &DiggerPolicyChecker{
PolicyProvider: tt.fields.PolicyProvider,
}
got, err := p.CheckPlanPolicy("", "", tt.planJsonOutput)
got, _, err := p.CheckPlanPolicy("", "", tt.planJsonOutput)
if (err != nil) != tt.wantErr {
t.Errorf("DiggerPolicyChecker.CheckPlanPolicy() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
4 changes: 2 additions & 2 deletions pkg/utils/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ func (t MockPolicyChecker) CheckAccessPolicy(ciService ci.OrgService, SCMOrganis
return false, nil
}

func (t MockPolicyChecker) CheckPlanPolicy(projectName string, command string, requestedBy string) (bool, error) {
return false, nil
func (t MockPolicyChecker) CheckPlanPolicy(projectName string, command string, requestedBy string) (bool, []string, error) {
return false, nil, nil
}

type MockPullRequestManager struct {
Expand Down