diff --git a/internal/daemon/controller/handlers/workers/worker_service.go b/internal/daemon/controller/handlers/workers/worker_service.go index 601e84a7fb..52ea12c3b3 100644 --- a/internal/daemon/controller/handlers/workers/worker_service.go +++ b/internal/daemon/controller/handlers/workers/worker_service.go @@ -3,6 +3,7 @@ package workers import ( "context" "fmt" + "strings" "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/auth" @@ -545,6 +546,17 @@ func validateUpdateRequest(req *pbs.UpdateWorkerRequest) error { if req.GetItem().GetConfigTags() != nil { badFields[globals.TagsField] = "This is a read only field." } + nameString := req.GetItem().GetName().String() + if !strutil.Printable(nameString) { + badFields[globals.NameField] = "Contains non-printable characters" + } + if strings.ToLower(nameString) != nameString { + badFields[globals.NameField] = "Must be all lowercase." + } + descriptionString := req.GetItem().GetDescription().String() + if !strutil.Printable(descriptionString) { + badFields[globals.DescriptionField] = "Contains non-printable characters." + } return badFields }, servers.WorkerPrefix) } @@ -577,6 +589,17 @@ func validateCreateRequest(req *pbs.CreateWorkerLedRequest) error { if req.GetItem().AuthorizedActions != nil { badFields[globals.AuthorizedActionsField] = readOnlyFieldMsg } + nameString := req.GetItem().GetName().String() + if !strutil.Printable(nameString) { + badFields[globals.NameField] = "Contains non-printable characters." + } + if strings.ToLower(nameString) != nameString { + badFields[globals.NameField] = "Must be all lowercase" + } + descriptionString := req.GetItem().GetDescription().String() + if !strutil.Printable(descriptionString) { + badFields[globals.DescriptionField] = "Contains non-printable characters." + } return badFields }) } diff --git a/internal/daemon/controller/handlers/workers/worker_service_test.go b/internal/daemon/controller/handlers/workers/worker_service_test.go index 20ef70d9ce..a09c0c530a 100644 --- a/internal/daemon/controller/handlers/workers/worker_service_test.go +++ b/internal/daemon/controller/handlers/workers/worker_service_test.go @@ -708,6 +708,45 @@ func TestUpdate(t *testing.T) { res: nil, err: handlers.ApiErrorWithCode(codes.InvalidArgument), }, + { + name: "Invalid name- uppercase", + req: &pbs.UpdateWorkerRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description", "address"}, + }, + Item: &pb.Worker{ + Name: wrapperspb.String("BADNAME"), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Invalid name- non-printable", + req: &pbs.UpdateWorkerRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description", "address"}, + }, + Item: &pb.Worker{ + Name: wrapperspb.String("\x00"), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Invalid description- nonprintable", + req: &pbs.UpdateWorkerRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description", "address"}, + }, + Item: &pb.Worker{ + Description: wrapperspb.String("\x00"), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/db/schema/migrations/oss/postgres/99/02_worker_controller_tables.up.sql b/internal/db/schema/migrations/oss/postgres/99/02_worker_controller_tables.up.sql index 1576402501..c0ebbfea6e 100644 --- a/internal/db/schema/migrations/oss/postgres/99/02_worker_controller_tables.up.sql +++ b/internal/db/schema/migrations/oss/postgres/99/02_worker_controller_tables.up.sql @@ -53,16 +53,18 @@ create table server_worker ( references iam_scope_global(scope_id) on delete cascade on update cascade, - description wt_description, + description wt_description + constraint description_only_has_printable_characters + check (description is null or description !~ '[^[:print:]]'), name wt_name -- server_worker_scope_id_name_uq defines an appropriate uniqueness constraint for name constraint worker_name_must_be_set_by_status check ( type != 'kms' or name is not null ) - constraint kms_name_must_be_lowercase - check (lower(trim(name)) = name and type = 'kms') - constraint kms_name_only_has_printable_characters - check (name !~ '[^[:print:]]' and type = 'kms'), + constraint name_must_be_lowercase + check (name is null or lower(trim(name)) = name) + constraint name_only_has_printable_characters + check (name is null or name !~ '[^[:print:]]'), address wt_network_address constraint address_must_be_set_by_status check (