diff --git a/internal/db/migrations/postgres.gen.go b/internal/db/migrations/postgres.gen.go index 0efc2d2bcf..dec5d38ed2 100644 --- a/internal/db/migrations/postgres.gen.go +++ b/internal/db/migrations/postgres.gen.go @@ -2425,7 +2425,7 @@ begin; description text, address text not null check( - length(trim(address)) > 7 + length(trim(address)) > 2 and length(trim(address)) < 256 ), diff --git a/internal/db/migrations/postgres/22_static_host.up.sql b/internal/db/migrations/postgres/22_static_host.up.sql index d240ffb6f8..94f5795149 100644 --- a/internal/db/migrations/postgres/22_static_host.up.sql +++ b/internal/db/migrations/postgres/22_static_host.up.sql @@ -84,7 +84,7 @@ begin; description text, address text not null check( - length(trim(address)) > 7 + length(trim(address)) > 2 and length(trim(address)) < 256 ), diff --git a/internal/host/static/host.go b/internal/host/static/host.go index b5aed120c2..ac025632f3 100644 --- a/internal/host/static/host.go +++ b/internal/host/static/host.go @@ -9,6 +9,11 @@ import ( "google.golang.org/protobuf/proto" ) +const ( + MinHostAddressLength = 3 + MaxHostAddressLength = 255 +) + // A Host contains a static address. type Host struct { *store.Host diff --git a/internal/host/static/host_test.go b/internal/host/static/host_test.go index 1a8496ab64..b4788c018e 100644 --- a/internal/host/static/host_test.go +++ b/internal/host/static/host_test.go @@ -54,12 +54,12 @@ func TestHost_New(t *testing.T) { name: "address-to-short", args: args{ catalogId: cat.GetPublicId(), - opts: []Option{WithAddress("1234567")}, + opts: []Option{WithAddress("12")}, }, want: &Host{ Host: &store.Host{ CatalogId: cat.GetPublicId(), - Address: "1234567", + Address: "12", }, }, wantWriteErr: true, @@ -68,12 +68,12 @@ func TestHost_New(t *testing.T) { name: "minimum-address", args: args{ catalogId: cat.GetPublicId(), - opts: []Option{WithAddress("12345678")}, + opts: []Option{WithAddress("123")}, }, want: &Host{ Host: &store.Host{ CatalogId: cat.GetPublicId(), - Address: "12345678", + Address: "123", }, }, }, diff --git a/internal/host/static/repository_host.go b/internal/host/static/repository_host.go index de9b482d31..bcdccd7b70 100644 --- a/internal/host/static/repository_host.go +++ b/internal/host/static/repository_host.go @@ -37,6 +37,10 @@ func (r *Repository) CreateHost(ctx context.Context, scopeId string, h *Host, op if scopeId == "" { return nil, fmt.Errorf("create: static host: no scopeId: %w", db.ErrInvalidParameter) } + h.Address = strings.TrimSpace(h.Address) + if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { + return nil, fmt.Errorf("create: static host: bad address: %w", ErrInvalidAddress) + } h = h.clone() id, err := newHostId() @@ -106,6 +110,10 @@ func (r *Repository) UpdateHost(ctx context.Context, scopeId string, h *Host, ve case strings.EqualFold("Name", f): case strings.EqualFold("Description", f): case strings.EqualFold("Address", f): + h.Address = strings.TrimSpace(h.Address) + if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host: bad address: %w", ErrInvalidAddress) + } default: return nil, db.NoRowsAffected, fmt.Errorf("update: static host: field: %s: %w", f, db.ErrInvalidFieldMask) } diff --git a/internal/host/static/repository_host_test.go b/internal/host/static/repository_host_test.go index c7d407b6d4..1da279412b 100644 --- a/internal/host/static/repository_host_test.go +++ b/internal/host/static/repository_host_test.go @@ -125,7 +125,7 @@ func TestRepository_CreateHost(t *testing.T) { in: &Host{ Host: &store.Host{ CatalogId: catalog.PublicId, - Address: "127", + Address: "12", }, }, wantIsErr: ErrInvalidAddress, diff --git a/internal/servers/controller/handlers/hosts/host_service.go b/internal/servers/controller/handlers/hosts/host_service.go index 0f05e700cf..2d97f7ae2d 100644 --- a/internal/servers/controller/handlers/hosts/host_service.go +++ b/internal/servers/controller/handlers/hosts/host_service.go @@ -3,6 +3,7 @@ package hosts import ( "context" "fmt" + "strings" "github.com/hashicorp/boundary/internal/auth" pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts" @@ -351,8 +352,10 @@ func validateCreateRequest(req *pbs.CreateHostRequest) error { if err := handlers.StructToProto(req.GetItem().GetAttributes(), attrs); err != nil { badFields["attributes"] = "Attribute fields do not match the expected format." } - if attrs.GetAddress() == nil { - badFields["attributes.address"] = "This is a required field for this type." + if attrs.GetAddress() == nil || + len(attrs.GetAddress().GetValue()) < static.MinHostAddressLength || + len(attrs.GetAddress().GetValue()) > static.MaxHostAddressLength { + badFields["attributes.address"] = fmt.Sprintf("Address length must be between %d and %d characters.", static.MinHostAddressLength, static.MaxHostAddressLength) } } return badFields @@ -366,6 +369,19 @@ func validateUpdateRequest(req *pbs.UpdateHostRequest) error { case host.StaticSubtype: if req.GetItem().GetType() != "" && req.GetItem().GetType() != host.StaticSubtype.String() { badFields["type"] = "Cannot modify the resource type." + + attrs := &pb.StaticHostAttributes{} + if err := handlers.StructToProto(req.GetItem().GetAttributes(), attrs); err != nil { + badFields["attributes"] = "Attribute fields do not match the expected format." + } + + if handlers.MaskContains(req.GetUpdateMask().GetPaths(), "attributes.address") { + if attrs.GetAddress() == nil || + len(strings.TrimSpace(attrs.GetAddress().GetValue())) < static.MinHostAddressLength || + len(strings.TrimSpace(attrs.GetAddress().GetValue())) > static.MaxHostAddressLength { + badFields["attributes.address"] = fmt.Sprintf("Address length must be between %d and %d characters.", static.MinHostAddressLength, static.MaxHostAddressLength) + } + } } default: badFields["id"] = "Improperly formatted identifier used." diff --git a/internal/servers/controller/handlers/hosts/host_service_test.go b/internal/servers/controller/handlers/hosts/host_service_test.go index ac43eef937..d3460e509a 100644 --- a/internal/servers/controller/handlers/hosts/host_service_test.go +++ b/internal/servers/controller/handlers/hosts/host_service_test.go @@ -304,6 +304,19 @@ func TestCreate(t *testing.T) { }, errCode: codes.OK, }, + { + name: "Create with empty address", + req: &pbs.CreateHostRequest{Item: &pb.Host{ + HostCatalogId: hc.GetPublicId(), + Name: &wrappers.StringValue{Value: "name"}, + Description: &wrappers.StringValue{Value: "desc"}, + Type: "static", + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "address": structpb.NewStringValue(""), + }}, + }}, + errCode: codes.InvalidArgument, + }, { name: "Create without address", req: &pbs.CreateHostRequest{Item: &pb.Host{ @@ -691,6 +704,36 @@ func TestUpdate(t *testing.T) { res: nil, errCode: codes.InvalidArgument, }, + { + name: "Cant unset address", + req: &pbs.UpdateHostRequest{ + Id: hc.GetPublicId(), + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"attributes.address"}, + }, + Item: &pb.Host{ + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "address": structpb.NewNullValue(), + }}, + }}, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Cant set address to empty string", + req: &pbs.UpdateHostRequest{ + Id: hc.GetPublicId(), + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"attributes.address"}, + }, + Item: &pb.Host{ + Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{ + "address": structpb.NewStringValue(""), + }}, + }}, + res: nil, + errCode: codes.InvalidArgument, + }, { name: "Cant specify Created Time", req: &pbs.UpdateHostRequest{