diff --git a/sdk/nanotdf.go b/sdk/nanotdf.go index 9f69295c8..0cb3a6b1c 100644 --- a/sdk/nanotdf.go +++ b/sdk/nanotdf.go @@ -199,8 +199,8 @@ const ( cipherModeAes256gcm128Bit CipherMode = 5 ) -const ( - ErrNanoTDFHeaderRead = Error("nanoTDF read error") +var ( + ErrNanoTDFHeaderRead = fmt.Errorf("nanoTDF read error [%w]", ErrParseFailed) ) // Binding config byte format diff --git a/sdk/resource_locator.go b/sdk/resource_locator.go index 13ed15e1f..df9ea1de9 100644 --- a/sdk/resource_locator.go +++ b/sdk/resource_locator.go @@ -132,18 +132,18 @@ func (rl ResourceLocator) writeResourceLocator(writer io.Writer) error { // readResourceLocator - read the encoded protocol and body string into a ResourceLocator func (rl *ResourceLocator) readResourceLocator(reader io.Reader) error { if err := binary.Read(reader, binary.BigEndian, &rl.protocol); err != nil { - return errors.Join(Error("Error reading ResourceLocator protocol value"), err) + return errors.Join(ErrParseFailed, Error("error reading ResourceLocator protocol value"), ErrParseFailed, err) } if (rl.protocol != urlProtocolHTTP) && (rl.protocol != urlProtocolHTTPS) { // TODO - support 'shared' protocol? return errors.New("Unsupported protocol: " + strconv.Itoa(int(rl.protocol))) } var lengthBody byte if err := binary.Read(reader, binary.BigEndian, &lengthBody); err != nil { - return errors.Join(Error("Error reading ResourceLocator body length value"), err) + return errors.Join(ErrParseFailed, Error("Error reading ResourceLocator body length value"), err) } body := make([]byte, lengthBody) if err := binary.Read(reader, binary.BigEndian, &body); err != nil { - return errors.Join(Error("Error reading ResourceLocator body value"), err) + return errors.Join(ErrParseFailed, Error("Error reading ResourceLocator body value"), err) } rl.body = string(body) // TODO - normalize to lowercase? return nil diff --git a/sdk/sdk.go b/sdk/sdk.go index ce07cf195..eea678168 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -33,9 +33,11 @@ const ( // Failure while connecting to a service. // Check your configuration and/or retry. ErrGrpcDialFailed = Error("failed to dial grpc endpoint") - ErrShutdownFailed = Error("failed to shutdown sdk") + ErrInvalidAttributes = Error("one or more attributes is invalid or undefined") + ErrParseFailed = Error("invalid file syntax or structure") ErrPlatformConfigFailed = Error("failed to retrieve platform configuration") ErrPlatformEndpointMalformed = Error("platform endpoint is malformed") + ErrShutdownFailed = Error("failed to shutdown sdk") ) type Error string diff --git a/sdk/tdf.go b/sdk/tdf.go index 59a5ccfc0..6772e6041 100644 --- a/sdk/tdf.go +++ b/sdk/tdf.go @@ -17,6 +17,8 @@ import ( "github.com/opentdf/platform/sdk/internal/archive" "github.com/opentdf/platform/sdk/internal/autoconfigure" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var ( @@ -136,6 +138,10 @@ func (s SDK) CreateTDFContext(ctx context.Context, writer io.Writer, reader io.R g, err = autoconfigure.NewGranterFromService(ctx, s.Attributes, tdfConfig.attributes...) } if err != nil { + if status.Code(err) == codes.NotFound { + // One or more attribute was not found + return nil, errors.Join(err, ErrInvalidAttributes) + } return nil, err } diff --git a/service/authorization/authorization.go b/service/authorization/authorization.go index 5a4e99df4..3723567d3 100644 --- a/service/authorization/authorization.go +++ b/service/authorization/authorization.go @@ -207,7 +207,7 @@ func (as *AuthorizationService) GetDecisions(ctx context.Context, req *authoriza if err != nil { // if attribute an FQN does not exist // return deny for all entity chains aginst this RA set and continue to next - if errors.Is(err, db.StatusifyError(db.ErrNotFound, "")) { + if errors.Is(err, db.ErrNotFound) { for _, ec := range dr.GetEntityChains() { decisionResp := &authorization.DecisionResponse{ Decision: authorization.DecisionResponse_DECISION_DENY, diff --git a/service/integration/attribute_fqns_test.go b/service/integration/attribute_fqns_test.go index b4f0919c3..a7c103746 100644 --- a/service/integration/attribute_fqns_test.go +++ b/service/integration/attribute_fqns_test.go @@ -722,6 +722,7 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedNa s.Require().NoError(err) // get the attribute by the value fqn for v1 + var nfe db.NotFoundError v, err := s.db.PolicyClient.GetAttributesByValueFqns(s.ctx, &attributes.GetAttributeValuesByFqnsRequest{ Fqns: []string{fqnBuilder(ns.GetName(), attr.GetName(), v1.GetValue())}, WithValue: &policy.AttributeValueSelector{ @@ -731,6 +732,8 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedNa s.Require().Error(err) s.Nil(v) s.Require().ErrorIs(err, db.ErrNotFound) + s.Require().ErrorAs(err, &nfe) + s.Contains(nfe.What, "https://test_fqn_namespace.co/attr/test_attr/value/value1") // get the attribute by the value fqn for v2 v, err = s.db.PolicyClient.GetAttributesByValueFqns(s.ctx, &attributes.GetAttributeValuesByFqnsRequest{ @@ -742,6 +745,8 @@ func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedNa s.Require().Error(err) s.Nil(v) s.Require().ErrorIs(err, db.ErrNotFound) + s.Require().ErrorAs(err, &nfe) + s.Contains(nfe.What, "https://test_fqn_namespace.co/attr/test_attr/value/value2") } func (s *AttributeFqnSuite) TestGetAttributesByValueFqns_Fails_WithDeactivatedAttributeDefinition() { diff --git a/service/pkg/db/errors.go b/service/pkg/db/errors.go index 0ca5ec5d2..4f451fda8 100644 --- a/service/pkg/db/errors.go +++ b/service/pkg/db/errors.go @@ -25,6 +25,18 @@ var ( ErrMissingValue = errors.New("ErrMissingValue: value must be included") ) +type NotFoundError struct { + What []string +} + +func (e NotFoundError) Error() string { + return fmt.Sprintf("not found: %v", e.What) +} + +func (e NotFoundError) Unwrap() error { + return ErrNotFound +} + // Get helpful error message for PostgreSQL violation func WrapIfKnownInvalidQueryErr(err error) error { if e := isPgError(err); e != nil { diff --git a/service/policy/db/attribute_fqn.go b/service/policy/db/attribute_fqn.go index a25d11e8f..d86d0150d 100644 --- a/service/policy/db/attribute_fqn.go +++ b/service/policy/db/attribute_fqn.go @@ -193,6 +193,9 @@ func (c *PolicyDBClient) GetAttributesByValueFqns(ctx context.Context, r *attrib attr, err := c.GetAttributeByFqn(ctx, fqn) if err != nil { c.logger.Error("could not get attribute by FQN", slog.String("fqn", fqn), slog.String("error", err.Error())) + if errors.Is(err, db.ErrNotFound) { + return nil, errors.Join(db.NotFoundError{What: []string{fqn}}, err) + } return nil, err } filtered, selected := prepareValues(attr.GetValues(), fqn)