Skip to content

Commit c7d6b15

Browse files
feat(policy): 1651 move GetAttributesByValueFqns RPC request validation to protovalidate (#1657)
fix #1651 --------- Co-authored-by: Jake Van Vorhis <[email protected]> Co-authored-by: jakedoublev <[email protected]>
1 parent ce10f3f commit c7d6b15

File tree

7 files changed

+326
-276
lines changed

7 files changed

+326
-276
lines changed

docs/grpc/index.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protocol/go/policy/attributes/attributes.pb.go

Lines changed: 255 additions & 254 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/integration/attribute_fqns_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithNonValueFqns(
14721472
})
14731473
s.Require().Error(err)
14741474
s.Nil(v)
1475-
s.Require().ErrorIs(err, db.ErrFqnMissingValue)
1475+
s.Require().ErrorIs(err, db.ErrNotFound)
14761476

14771477
v, err = s.db.PolicyClient.GetAttributesByValueFqns(s.ctx, &attributes.GetAttributeValuesByFqnsRequest{
14781478
Fqns: []string{attrFqn},
@@ -1482,5 +1482,5 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithNonValueFqns(
14821482
})
14831483
s.Require().Error(err)
14841484
s.Nil(v)
1485-
s.Require().ErrorIs(err, db.ErrFqnMissingValue)
1485+
s.Require().ErrorIs(err, db.ErrNotFound)
14861486
}

service/pkg/db/errors.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ var (
2121
ErrNotFound = errors.New("ErrNotFound: value not found")
2222
ErrEnumValueInvalid = errors.New("ErrEnumValueInvalid: not a valid enum value")
2323
ErrUUIDInvalid = errors.New("ErrUUIDInvalid: value not a valid UUID")
24-
ErrFqnMissingValue = errors.New("ErrFqnMissingValue: FQN must include a value")
2524
ErrMissingValue = errors.New("ErrMissingValue: value must be included")
2625
)
2726

@@ -127,10 +126,6 @@ func StatusifyError(err error, fallbackErr string, log ...any) error {
127126
slog.Error(ErrTextRestrictViolation, l...)
128127
return status.Error(codes.InvalidArgument, ErrTextRestrictViolation)
129128
}
130-
if errors.Is(err, ErrFqnMissingValue) {
131-
slog.Error(ErrTextFqnMissingValue, l...)
132-
return status.Error(codes.InvalidArgument, ErrTextFqnMissingValue)
133-
}
134129
slog.Error(err.Error(), l...)
135130
return status.Error(codes.Internal, fallbackErr)
136131
}

service/policy/attributes/attributes.proto

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,16 @@ message DeactivateAttributeValueResponse {
214214
message GetAttributeValuesByFqnsRequest {
215215
// Required
216216
// Fully Qualified Names of attribute values (i.e. https://<namespace>/attr/<attribute_name>/value/<value_name>), normalized to lower case.
217-
repeated string fqns = 1 [(buf.validate.field).required = true];
218-
policy.AttributeValueSelector with_value = 2 [(buf.validate.field).required = true];
217+
repeated string fqns = 1 [
218+
(buf.validate.field).repeated = {
219+
min_items: 1,
220+
max_items: 250
221+
}
222+
];
223+
224+
// Optional
225+
// This attribute value selector is not used currently, but left here for future use.
226+
policy.AttributeValueSelector with_value = 2;
219227
}
220228
message GetAttributeValuesByFqnsResponse {
221229
message AttributeAndValue {

service/policy/attributes/attributes_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package attributes
22

33
import (
4+
"fmt"
45
"strings"
56
"testing"
67

@@ -451,3 +452,59 @@ func TestDeactivateAttributeValueRequest(t *testing.T) {
451452
err = getValidator().Validate(req)
452453
require.NoError(t, err)
453454
}
455+
456+
func TestGetAttributeValuesByFqns_Valid_Succeeds(t *testing.T) {
457+
req := &attributes.GetAttributeValuesByFqnsRequest{
458+
Fqns: []string{
459+
"any_value",
460+
},
461+
}
462+
463+
v := getValidator()
464+
err := v.Validate(req)
465+
466+
require.NoError(t, err)
467+
}
468+
469+
func TestGetAttributeValuesByFqns_FQNsNil_Fails(t *testing.T) {
470+
req := &attributes.GetAttributeValuesByFqnsRequest{}
471+
472+
v := getValidator()
473+
err := v.Validate(req)
474+
475+
require.Error(t, err)
476+
require.Contains(t, err.Error(), "fqns")
477+
require.Contains(t, err.Error(), "[repeated.min_items]")
478+
}
479+
480+
func TestGetAttributeValuesByFqns_FQNsEmpty_Fails(t *testing.T) {
481+
req := &attributes.GetAttributeValuesByFqnsRequest{
482+
Fqns: []string{},
483+
}
484+
485+
v := getValidator()
486+
err := v.Validate(req)
487+
488+
require.Error(t, err)
489+
require.Contains(t, err.Error(), "fqns")
490+
require.Contains(t, err.Error(), "[repeated.min_items]")
491+
}
492+
493+
func TestGetAttributeValuesByFqns_FQNsOutsideMaxItemsRange_Fails(t *testing.T) {
494+
outsideRange := 251
495+
fqns := make([]string, outsideRange)
496+
for i := 0; i < outsideRange; i++ {
497+
fqns[i] = fmt.Sprintf("fqn_%d", i)
498+
}
499+
500+
req := &attributes.GetAttributeValuesByFqnsRequest{
501+
Fqns: fqns,
502+
}
503+
504+
v := getValidator()
505+
err := v.Validate(req)
506+
507+
require.Error(t, err)
508+
require.Contains(t, err.Error(), "fqns")
509+
require.Contains(t, err.Error(), "[repeated.max_items]")
510+
}

service/policy/db/attribute_fqn.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package db
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"strings"
87

@@ -71,23 +70,12 @@ func (c *PolicyDBClient) AttrFqnReindex(ctx context.Context) (res struct { //nol
7170
func (c *PolicyDBClient) GetAttributesByValueFqns(ctx context.Context, r *attributes.GetAttributeValuesByFqnsRequest) (map[string]*attributes.GetAttributeValuesByFqnsResponse_AttributeAndValue, error) {
7271
fqns := r.GetFqns()
7372

74-
// todo: move to proto validation
75-
if fqns == nil || r.GetWithValue() == nil {
76-
return nil, errors.Join(db.ErrMissingValue, errors.New("error: one or more FQNs and a WithValue selector must be provided"))
77-
}
78-
7973
list := make(map[string]*attributes.GetAttributeValuesByFqnsResponse_AttributeAndValue, len(fqns))
8074

8175
for i, fqn := range fqns {
8276
// normalize to lower case
8377
fqn = strings.ToLower(fqn)
8478

85-
// ensure the FQN corresponds to an attribute value and not a definition or namespace alone
86-
// todo: move to proto validation
87-
if !strings.Contains(fqn, "/value/") {
88-
return nil, db.ErrFqnMissingValue
89-
}
90-
9179
// update array with normalized FQN
9280
fqns[i] = fqn
9381

0 commit comments

Comments
 (0)