diff --git a/backend/remote/backend_apply_test.go b/backend/remote/backend_apply_test.go index 8a419a573..355f1c506 100644 --- a/backend/remote/backend_apply_test.go +++ b/backend/remote/backend_apply_test.go @@ -1151,6 +1151,7 @@ func TestRemote_applyPolicySoftFail(t *testing.T) { "approve": "yes", }) + op.AutoApprove = false op.UIIn = input op.UIOut = b.CLI op.Workspace = backend.DefaultStateName @@ -1187,16 +1188,14 @@ func TestRemote_applyPolicySoftFail(t *testing.T) { } } -func TestRemote_applyPolicySoftFailAutoApprove(t *testing.T) { +func TestRemote_applyPolicySoftFailAutoApproveSuccess(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() op, configCleanup, done := testOperationApply(t, "./testdata/apply-policy-soft-failed") defer configCleanup() - input := testInput(t, map[string]string{ - "override": "override", - }) + input := testInput(t, map[string]string{}) op.AutoApprove = true op.UIIn = input @@ -1210,34 +1209,33 @@ func TestRemote_applyPolicySoftFailAutoApprove(t *testing.T) { <-run.Done() viewOutput := done(t) - if run.Result == backend.OperationSuccess { - t.Fatal("expected apply operation to fail") - } - if !run.PlanEmpty { - t.Fatalf("expected plan to be empty") + if run.Result != backend.OperationSuccess { + t.Fatal("expected apply operation to success due to auto-approve") } - if len(input.answers) != 1 { - t.Fatalf("expected an unused answers, got: %v", input.answers) + if run.PlanEmpty { + t.Fatalf("expected plan to not be empty, plan opertion completed without error") + } + + if len(input.answers) != 0 { + t.Fatalf("expected no answers, got: %v", input.answers) } errOutput := viewOutput.Stderr() - if !strings.Contains(errOutput, "soft failed") { - t.Fatalf("expected a policy check error, got: %v", errOutput) + if strings.Contains(errOutput, "soft failed") { + t.Fatalf("expected no policy check errors, instead got: %v", errOutput) } output := b.CLI.(*cli.MockUi).OutputWriter.String() - if !strings.Contains(output, "Running apply in the remote backend") { - t.Fatalf("expected remote backend header in output: %s", output) - } - if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") { - t.Fatalf("expected plan summery in output: %s", output) - } if !strings.Contains(output, "Sentinel Result: false") { - t.Fatalf("expected policy check result in output: %s", output) + t.Fatalf("expected policy check to be false, insead got: %s", output) } - if strings.Contains(output, "1 added, 0 changed, 0 destroyed") { - t.Fatalf("unexpected apply summery in output: %s", output) + if !strings.Contains(output, "Apply complete!") { + t.Fatalf("expected apply to be complete, instead got: %s", output) + } + + if !strings.Contains(output, "Resources: 1 added, 0 changed, 0 destroyed") { + t.Fatalf("expected resources, instead got: %s", output) } } diff --git a/backend/remote/backend_common.go b/backend/remote/backend_common.go index fb390acad..7346324ce 100644 --- a/backend/remote/backend_common.go +++ b/backend/remote/backend_common.go @@ -414,34 +414,45 @@ func (b *Remote) checkPolicy(stopCtx, cancelCtx context.Context, op *backend.Ope case tfe.PolicyHardFailed: return fmt.Errorf(msgPrefix + " hard failed.") case tfe.PolicySoftFailed: + runUrl := fmt.Sprintf(runHeader, b.hostname, b.organization, op.Workspace, r.ID) + if op.Type == backend.OperationTypePlan || op.UIOut == nil || op.UIIn == nil || - op.AutoApprove || !pc.Actions.IsOverridable || !pc.Permissions.CanOverride { - return fmt.Errorf(msgPrefix + " soft failed.") + !pc.Actions.IsOverridable || !pc.Permissions.CanOverride { + return fmt.Errorf(msgPrefix + " soft failed.\n" + runUrl) + } + + if op.AutoApprove { + if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil { + return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err) + } + } else { + opts := &terraform.InputOpts{ + Id: "override", + Query: "\nDo you want to override the soft failed policy check?", + Description: "Only 'override' will be accepted to override.", + } + err = b.confirm(stopCtx, op, opts, r, "override") + if err != nil && err != errRunOverridden { + return fmt.Errorf( + fmt.Sprintf("Failed to override: %s\n%s\n", err.Error(), runUrl), + ) + } + + if err != errRunOverridden { + if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil { + return generalError(fmt.Sprintf("Failed to override policy check.\n%s", runUrl), err) + } + } else { + b.CLI.Output(fmt.Sprintf("The run needs to be manually overridden or discarded.\n%s\n", runUrl)) + } + } + + if b.CLI != nil { + b.CLI.Output("------------------------------------------------------------------------") } default: return fmt.Errorf("Unknown or unexpected policy state: %s", pc.Status) } - - opts := &terraform.InputOpts{ - Id: "override", - Query: "\nDo you want to override the soft failed policy check?", - Description: "Only 'override' will be accepted to override.", - } - - err = b.confirm(stopCtx, op, opts, r, "override") - if err != nil && err != errRunOverridden { - return err - } - - if err != errRunOverridden { - if _, err = b.client.PolicyChecks.Override(stopCtx, pc.ID); err != nil { - return generalError("Failed to override policy check", err) - } - } - - if b.CLI != nil { - b.CLI.Output("------------------------------------------------------------------------") - } } return nil