Skip to content

feat!: Validate monotonic numbers for rich parameters #6046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Validation in coderd
  • Loading branch information
mtojek committed Feb 6, 2023
commit c1097ee1c31bdb2e9fae2ec990bc9ca7c820cb93
2 changes: 1 addition & 1 deletion cli/cliui/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,5 @@ func validateRichPrompt(value string, p codersdk.TemplateVersionParameter) error
return codersdk.ValidateWorkspaceBuildParameter(p, codersdk.WorkspaceBuildParameter{
Name: p.Name,
Value: value,
})
}, nil)
}
14 changes: 7 additions & 7 deletions coderd/workspacebuilds.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,24 +467,24 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
return
}

err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createBuild.RichParameterValues)
lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Error validating workspace build parameters.",
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching prior workspace build parameters.",
Detail: err.Error(),
})
return
}
apiLastBuildParameters := convertWorkspaceBuildParameters(lastBuildParameters)

lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID)
err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createBuild.RichParameterValues, apiLastBuildParameters)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching prior workspace build parameters.",
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Error validating workspace build parameters.",
Detail: err.Error(),
})
return
}
apiLastBuildParameters := convertWorkspaceBuildParameters(lastBuildParameters)

var parameters []codersdk.WorkspaceBuildParameter
for _, templateVersionParameter := range templateVersionParameters {
Expand Down
20 changes: 20 additions & 0 deletions coderd/workspacebuilds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,18 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) {
{Name: boolParameterName, Type: "bool", Mutable: true},
}

monotonicIncreasingNumberRichParameters := []*proto.RichParameter{
{Name: stringParameterName, Type: "string", Mutable: true},
{Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "increasing"},
{Name: boolParameterName, Type: "bool", Mutable: true},
}

monotonicDecreasingNumberRichParameters := []*proto.RichParameter{
{Name: stringParameterName, Type: "string", Mutable: true},
{Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "decreasing"},
{Name: boolParameterName, Type: "bool", Mutable: true},
}

stringRichParameters := []*proto.RichParameter{
{Name: stringParameterName, Type: "string", Mutable: true},
{Name: numberParameterName, Type: "number", Mutable: true},
Expand Down Expand Up @@ -900,6 +912,14 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) {
{numberParameterName, "10", true, numberRichParameters},
{numberParameterName, "11", false, numberRichParameters},

{numberParameterName, "6", false, monotonicIncreasingNumberRichParameters},
{numberParameterName, "7", true, monotonicIncreasingNumberRichParameters},
{numberParameterName, "8", true, monotonicIncreasingNumberRichParameters},

{numberParameterName, "6", true, monotonicDecreasingNumberRichParameters},
{numberParameterName, "7", true, monotonicDecreasingNumberRichParameters},
{numberParameterName, "8", false, monotonicDecreasingNumberRichParameters},

{stringParameterName, "", true, stringRichParameters},
{stringParameterName, "foobar", true, stringRichParameters},

Expand Down
2 changes: 1 addition & 1 deletion coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
return
}

err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createWorkspace.RichParameterValues)
err = codersdk.ValidateNewWorkspaceParameters(templateVersionParameters, createWorkspace.RichParameterValues)
if err != nil {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Error validating workspace build parameters.",
Expand Down
42 changes: 35 additions & 7 deletions codersdk/richparameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import (
"github.com/coder/terraform-provider-coder/provider"
)

func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, buildParameters []WorkspaceBuildParameter) error {
func ValidateNewWorkspaceParameters(richParameters []TemplateVersionParameter, buildParameters []WorkspaceBuildParameter) error {
return ValidateWorkspaceBuildParameters(richParameters, buildParameters, nil)
}

func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, buildParameters, lastBuildParameters []WorkspaceBuildParameter) error {
for _, buildParameter := range buildParameters {
if buildParameter.Name == "" {
return xerrors.Errorf(`workspace build parameter name is missing`)
Expand All @@ -16,20 +20,33 @@ func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter,
return xerrors.Errorf(`workspace build parameter is not defined in the template ("coder_parameter"): %s`, buildParameter.Name)
}

err := ValidateWorkspaceBuildParameter(*richParameter, buildParameter)
err := ValidateWorkspaceBuildParameter(*richParameter, buildParameter, findLastBuildParameter(lastBuildParameters, buildParameter.Name))
if err != nil {
return xerrors.Errorf("can't validate build parameter %q: %w", buildParameter.Name, err)
}
}
return nil
}

func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, buildParameter WorkspaceBuildParameter) error {
func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, buildParameter WorkspaceBuildParameter, lastBuildParameter *WorkspaceBuildParameter) error {
value := buildParameter.Value
if value == "" {
value = richParameter.DefaultValue
}

if lastBuildParameter != nil && richParameter.Type == "number" && len(richParameter.ValidationMonotonic) > 0 {
switch richParameter.ValidationMonotonic {
case MonotonicOrderIncreasing:
if lastBuildParameter.Value > buildParameter.Value {
return xerrors.Errorf("parameter value must be equal or lower than previous value: %s", lastBuildParameter.Value)
}
case MonotonicOrderDecreasing:
if lastBuildParameter.Value < buildParameter.Value {
return xerrors.Errorf("parameter value must be equal or greater than previous value: %s", lastBuildParameter.Value)
}
}
}

if len(richParameter.Options) > 0 {
var matched bool
for _, opt := range richParameter.Options {
Expand All @@ -50,10 +67,11 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui
}

validation := &provider.Validation{
Min: int(richParameter.ValidationMin),
Max: int(richParameter.ValidationMax),
Regex: richParameter.ValidationRegex,
Error: richParameter.ValidationError,
Min: int(richParameter.ValidationMin),
Max: int(richParameter.ValidationMax),
Regex: richParameter.ValidationRegex,
Error: richParameter.ValidationError,
Monotonic: string(richParameter.ValidationMonotonic),
}
return validation.Valid(richParameter.Type, value)
}
Expand All @@ -67,6 +85,15 @@ func findTemplateVersionParameter(params []TemplateVersionParameter, parameterNa
return nil, false
}

func findLastBuildParameter(params []WorkspaceBuildParameter, parameterName string) *WorkspaceBuildParameter {
for _, p := range params {
if p.Name == parameterName {
return &p
}
}
return nil
}

func parameterValuesAsArray(options []TemplateVersionParameterOption) []string {
var arr []string
for _, opt := range options {
Expand All @@ -78,5 +105,6 @@ func parameterValuesAsArray(options []TemplateVersionParameterOption) []string {
func validationEnabled(param TemplateVersionParameter) bool {
return len(param.ValidationRegex) > 0 ||
(param.ValidationMin != 0 && param.ValidationMax != 0) ||
len(param.ValidationMonotonic) > 0 ||
param.Type == "bool" // boolean type doesn't have any custom validation rules, but the value must be checked (true/false).
}
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ require (
github.com/charmbracelet/lipgloss v0.6.0
github.com/cli/safeexec v1.0.0
github.com/coder/retry v1.3.0
github.com/coder/terraform-provider-coder v0.6.9
github.com/coder/terraform-provider-coder v0.6.11
github.com/coreos/go-oidc/v3 v3.4.0
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/creack/pty v1.1.18
Expand Down Expand Up @@ -174,14 +174,18 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
github.com/hashicorp/go-hclog v1.2.1 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.12.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0 // indirect
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c // indirect
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3 h1:lq8GmpE5bn8A3
github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3/go.mod h1:lkCb74eSJwxeNq8YwyILoHD5vtHktiZnTOxBxo3tbNc=
github.com/coder/terraform-provider-coder v0.6.9 h1:8WKYCwc3kq6Be/cjzrCKydbGB464xfGpnHHCzJULVA0=
github.com/coder/terraform-provider-coder v0.6.9/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY=
github.com/coder/terraform-provider-coder v0.6.11 h1:xdzopnSgy6bMBQlIkAgyyF0m6C3HzEQiF9DnHYpbIFU=
github.com/coder/terraform-provider-coder v0.6.11/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
Expand Down Expand Up @@ -1003,6 +1005,7 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ=
github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b h1:3GrpnZQBxcMj1gCXQLelfjCT1D5MPGTuGMKHVzSIH6A=
github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b/go.mod h1:qIFzeFcJU3OIFk/7JreWXcUjFmcCaeHTH9KoNyHYVCs=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
Expand All @@ -1013,6 +1016,7 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
Expand Down Expand Up @@ -1049,7 +1053,9 @@ github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfD
github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0 h1:+KxZULPsbjpAVoP0WNj/8aVW6EqpcX5JcUcQ5wl7Da4=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0/go.mod h1:DwGJG3KNxIPluVk6hexvDfYR/MS/eKGpiztJoT3Bbbw=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce h1:7FO+LmZwiG/eDsBWo50ZeqV5PoH0gwiM1mxFajXAkas=
github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU=
Expand Down Expand Up @@ -1458,6 +1464,7 @@ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
Expand Down Expand Up @@ -2123,6 +2130,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand Down