Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

internal/server: Add many validations to authenticated endpoints #2273

Merged
merged 18 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from 17 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
4 changes: 4 additions & 0 deletions .changelog/2273.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
```release-note:bug
server: Adds API validation to ensure server doesn't panic when given an empty
request body
```
10 changes: 10 additions & 0 deletions internal/server/ptypes/application.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ptypes

import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/imdario/mergo"
"github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require"

"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
)

Expand All @@ -26,3 +28,11 @@ func TestApplication(t testing.T, src *pb.Application) *pb.Application {

return src
}

// ValidateUpsertApplicationRequest
func ValidateUpsertApplicationRequest(v *pb.UpsertApplicationRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Project, validation.Required),
validation.Field(&v.Name, validation.Required),
))
}
88 changes: 88 additions & 0 deletions internal/server/ptypes/artifact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package ptypes

import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/imdario/mergo"
"github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require"

"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
)

// TestArtifact returns a valid user for tests.
func TestArtifact(t testing.T, src *pb.PushedArtifact) *pb.PushedArtifact {
t.Helper()

if src == nil {
src = &pb.PushedArtifact{}
}

require.NoError(t, mergo.Merge(src, &pb.PushedArtifact{
Id: "test",
}))

return src
}

// ValidatePushedArtifact validates the user structure.
func ValidatePushedArtifact(v *pb.PushedArtifact) error {
return validationext.Error(validation.ValidateStruct(v,
ValidatePushedArtifactRules(v)...,
))
}

// ValidatePushedArtifactRules
func ValidatePushedArtifactRules(v *pb.PushedArtifact) []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Artifact, validation.Required),

validationext.StructField(&v.Application, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Application.Application, validation.Required),
validation.Field(&v.Application.Project, validation.Required),
}
}),

validationext.StructField(&v.Workspace, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Workspace.Workspace, validation.Required),
}
}),
}
}

// ValidateUpsertArtifactRequest
func ValidateUpsertPushedArtifactRequest(v *pb.UpsertPushedArtifactRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Artifact, validation.Required),
))
}

// ValidateListPushedArtifactsRequest
func ValidateListPushedArtifactsRequest(v *pb.ListPushedArtifactsRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validationext.StructField(&v.Application, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Application.Application, validation.Required),
validation.Field(&v.Application.Project, validation.Required),
}
})))
}

// ValidateGetLatestPushedArtifactRequest
func ValidateGetLatestPushedArtifactRequest(v *pb.GetLatestPushedArtifactRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Application, validation.Required),
))
}

// ValidateGetPushedArtifactRequest
func ValidateGetPushedArtifactRequest(v *pb.GetPushedArtifactRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Ref, validation.Required),
validationext.StructField(&v.Ref, func() []*validation.FieldRules {
return ValidateRefOperationRules(v.Ref)
}),
))
}
9 changes: 8 additions & 1 deletion internal/server/ptypes/auth_method.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"go/token"

"github.com/go-ozzo/ozzo-validation/v4"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/hashicorp/go-bexpr"
"github.com/imdario/mergo"
Expand Down Expand Up @@ -90,6 +90,13 @@ func ValidateDeleteAuthMethodRequest(v *pb.DeleteAuthMethodRequest) error {
))
}

// ValidateGetAuthMethodRequest
func ValidateGetAuthMethodRequest(v *pb.GetAuthMethodRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.AuthMethod, validation.Required),
))
}

// ValidateGetOIDCAuthURLRequest
func ValidateGetOIDCAuthURLRequest(v *pb.GetOIDCAuthURLRequest) error {
return validationext.Error(validation.ValidateStruct(v,
Expand Down
89 changes: 89 additions & 0 deletions internal/server/ptypes/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ptypes

import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/imdario/mergo"
"github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require"

"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
)

// TestBuild returns a valid user for tests.
func TestBuild(t testing.T, src *pb.Build) *pb.Build {
t.Helper()

if src == nil {
src = &pb.Build{}
}

require.NoError(t, mergo.Merge(src, &pb.Build{
Id: "test",
}))

return src
}

// ValidateBuild validates the user structure.
func ValidateBuild(v *pb.Build) error {
return validationext.Error(validation.ValidateStruct(v,
ValidateBuildRules(v)...,
))
}

// ValidateBuildRules
func ValidateBuildRules(v *pb.Build) []*validation.FieldRules {
return []*validation.FieldRules{
validationext.StructField(&v.Application, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Application.Application, validation.Required),
validation.Field(&v.Application.Project, validation.Required),
}
}),

validationext.StructField(&v.Workspace, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Workspace.Workspace, validation.Required),
}
}),
}
}

// ValidateGetBuildRequest
func ValidateGetBuildRequest(v *pb.GetBuildRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Ref, validation.Required),
validationext.StructField(&v.Ref, func() []*validation.FieldRules {
return ValidateRefOperationRules(v.Ref)
}),
))
}

// ValidateListBuildsRequest
func ValidateListBuildsRequest(v *pb.ListBuildsRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validationext.StructField(&v.Application, func() []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Application.Application, validation.Required),
validation.Field(&v.Application.Project, validation.Required),
}
})))
}

// ValidateGetLatestBuildRequest
func ValidateGetLatestBuildRequest(v *pb.GetLatestBuildRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Application, validation.Required),
))
}

// ValidateUpsertBuildRequest
func ValidateUpsertBuildRequest(v *pb.UpsertBuildRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Build, validation.Required),
validationext.StructField(&v.Build, func() []*validation.FieldRules {
return ValidateBuildRules(v.Build)
}),
))
}
28 changes: 28 additions & 0 deletions internal/server/ptypes/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ptypes

import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
)

// ValidateSetConfigSourceRequest
func ValidateSetConfigSourceRequest(v *pb.SetConfigSourceRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.ConfigSource, validation.Required),
))
}

// ValidateGetConfigRequest
func ValidateGetConfigRequest(v *pb.ConfigGetRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Scope, validation.Required),
))
}

// ValidateGetConfigRequest
func ValidateGetConfigSourceRequest(v *pb.GetConfigSourceRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Scope, validation.Required),
))
}
43 changes: 43 additions & 0 deletions internal/server/ptypes/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,26 @@ import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
"github.com/imdario/mergo"
"github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require"
)

// TestDeployment returns a valid project for tests.
func TestDeployment(t testing.T, src *pb.Deployment) *pb.Deployment {
t.Helper()

if src == nil {
src = &pb.Deployment{}
}

require.NoError(t, mergo.Merge(src, &pb.Deployment{
Id: "test",
}))

return src
}

// Type wrapper around the proto type so that we can add some methods.
type Deployment struct{ *pb.Deployment }

Expand All @@ -25,6 +43,31 @@ func (v *Deployment) URLFragment() string {
return "v" + strconv.FormatUint(seq, 10)
}

// ValidateDeployment validates the project structure.
func ValidateDeployment(v *pb.Deployment) error {
return validationext.Error(validation.ValidateStruct(v,
ValidateDeploymentRules(v)...,
))
}

// ValidateDeploymentRules
func ValidateDeploymentRules(v *pb.Deployment) []*validation.FieldRules {
return []*validation.FieldRules{
validation.Field(&v.Application, validation.Required),
validation.Field(&v.Workspace, validation.Required),
}
}

// ValidateUpsertDeploymentRequest
func ValidateUpsertDeploymentRequest(v *pb.UpsertDeploymentRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Deployment, validation.Required),
validationext.StructField(&v.Deployment, func() []*validation.FieldRules {
return ValidateDeploymentRules(v.Deployment)
}),
))
}

// ValidateGetDeploymentRequest
func ValidateGetDeploymentRequest(v *pb.GetDeploymentRequest) error {
return validationext.Error(validation.ValidateStruct(v,
Expand Down
14 changes: 14 additions & 0 deletions internal/server/ptypes/hostname.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ptypes

import (
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/hashicorp/waypoint/internal/pkg/validationext"
pb "github.com/hashicorp/waypoint/internal/server/gen"
)

// ValidateCreateHostnameRequest
func ValidateCreateHostnameRequest(v *pb.CreateHostnameRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Target, validation.Required),
))
}
3 changes: 2 additions & 1 deletion internal/server/ptypes/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"

"github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/go-ozzo/ozzo-validation/v4"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/imdario/mergo"
"github.com/mitchellh/go-testing-interface"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -50,6 +50,7 @@ func TestJobNew(t testing.T, src *pb.Job) *pb.Job {
}

// ValidateJob validates the job structure.
// TODO: This still fails if the job passed in to be validated is nil
func ValidateJob(job *pb.Job) error {
return validationext.Error(validation.ValidateStruct(job,
validation.Field(&job.Id, validation.By(isEmpty)),
Expand Down
7 changes: 7 additions & 0 deletions internal/server/ptypes/ondemand_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ func ValidateUpsertOnDemandRunnerConfigRequest(v *pb.UpsertOnDemandRunnerConfigR
))
}

// ValidateGetOnDemandRunnerConfigRequest
func ValidateGetOnDemandRunnerConfigRequest(v *pb.GetOnDemandRunnerConfigRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Config, validation.Required),
))
}

func isPluginHcl(p *pb.OnDemandRunnerConfig) validation.Rule {
return validation.By(func(_ interface{}) error {
if len(p.PluginConfig) == 0 {
Expand Down
16 changes: 15 additions & 1 deletion internal/server/ptypes/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"errors"
"strings"

"github.com/go-ozzo/ozzo-validation/v4"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
hcljson "github.com/hashicorp/hcl/v2/json"
Expand Down Expand Up @@ -81,6 +81,20 @@ func ValidateUpsertProjectRequest(v *pb.UpsertProjectRequest) error {
))
}

// ValidateGetProjectRequest
func ValidateGetProjectRequest(v *pb.GetProjectRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Project, validation.Required),
))
}

// ValidateGetProjectRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[sand] This comment doesn’t match the function below it. But also: these comments don’t add much, could we drop them altogether?

Copy link
Member Author

@briancain briancain Sep 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yeah probably from all the copy paste to get the bare functions around before adding the content :D I can just fix the comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I were to do this again I'd probably delete them but now that they are there I'll probably leave them be 😅

func ValidateUIGetProjectRequest(v *pb.UI_GetProjectRequest) error {
return validationext.Error(validation.ValidateStruct(v,
validation.Field(&v.Project, validation.Required),
))
}

func isWaypointHcl(p *pb.Project) validation.Rule {
return validation.By(func(_ interface{}) error {
if len(p.WaypointHcl) == 0 {
Expand Down
Loading