summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/internal/relationships/errors.go
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
committermo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
commit20ef0d92694465ac86b550df139e8366a0a2b4fa (patch)
tree3f14589e1ce6eb9306a3af31c3a1f9e1af5ed637 /vendor/github.com/authzed/spicedb/internal/relationships/errors.go
parent44e0d272c040cdc53a98b9f1dc58ae7da67752e6 (diff)
feat: connect to spicedb
Diffstat (limited to 'vendor/github.com/authzed/spicedb/internal/relationships/errors.go')
-rw-r--r--vendor/github.com/authzed/spicedb/internal/relationships/errors.go195
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/spicedb/internal/relationships/errors.go b/vendor/github.com/authzed/spicedb/internal/relationships/errors.go
new file mode 100644
index 0000000..3237e0b
--- /dev/null
+++ b/vendor/github.com/authzed/spicedb/internal/relationships/errors.go
@@ -0,0 +1,195 @@
+package relationships
+
+import (
+ "fmt"
+ "maps"
+ "sort"
+ "strings"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+
+ v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
+ "github.com/lithammer/fuzzysearch/fuzzy"
+
+ "github.com/authzed/spicedb/pkg/genutil/mapz"
+ core "github.com/authzed/spicedb/pkg/proto/core/v1"
+ "github.com/authzed/spicedb/pkg/schema"
+ "github.com/authzed/spicedb/pkg/spiceerrors"
+ "github.com/authzed/spicedb/pkg/tuple"
+)
+
+// InvalidSubjectTypeError indicates that a write was attempted with a subject type which is not
+// allowed on relation.
+type InvalidSubjectTypeError struct {
+ error
+ relationship tuple.Relationship
+ relationType *core.AllowedRelation
+ additionalDetails map[string]string
+}
+
+// NewInvalidSubjectTypeError constructs a new error for attempting to write an invalid subject type.
+func NewInvalidSubjectTypeError(
+ relationship tuple.Relationship,
+ relationType *core.AllowedRelation,
+ definition *schema.Definition,
+) error {
+ allowedTypes, err := definition.AllowedDirectRelationsAndWildcards(relationship.Resource.Relation)
+ if err != nil {
+ return err
+ }
+
+ // Special case: if the subject is uncaveated but only a caveated version is allowed, return
+ // a more descriptive error.
+ if relationship.OptionalCaveat == nil {
+ allowedCaveatsForSubject := mapz.NewSet[string]()
+
+ for _, allowedType := range allowedTypes {
+ if allowedType.RequiredCaveat != nil &&
+ allowedType.RequiredCaveat.CaveatName != "" &&
+ allowedType.Namespace == relationship.Subject.ObjectType &&
+ allowedType.GetRelation() == relationship.Subject.Relation &&
+ (allowedType.RequiredExpiration != nil) == (relationship.OptionalExpiration != nil) {
+ allowedCaveatsForSubject.Add(allowedType.RequiredCaveat.CaveatName)
+ }
+ }
+
+ if !allowedCaveatsForSubject.IsEmpty() {
+ return InvalidSubjectTypeError{
+ error: fmt.Errorf(
+ "subjects of type `%s` are not allowed on relation `%s#%s` without one of the following caveats: %s",
+ schema.SourceForAllowedRelation(relationType),
+ relationship.Resource.ObjectType,
+ relationship.Resource.Relation,
+ strings.Join(allowedCaveatsForSubject.AsSlice(), ","),
+ ),
+ relationship: relationship,
+ relationType: relationType,
+ additionalDetails: map[string]string{
+ "allowed_caveats": strings.Join(allowedCaveatsForSubject.AsSlice(), ","),
+ },
+ }
+ }
+ }
+
+ allowedTypeStrings := make([]string, 0, len(allowedTypes))
+ for _, allowedType := range allowedTypes {
+ allowedTypeStrings = append(allowedTypeStrings, schema.SourceForAllowedRelation(allowedType))
+ }
+
+ matches := fuzzy.RankFind(schema.SourceForAllowedRelation(relationType), allowedTypeStrings)
+ sort.Sort(matches)
+ if len(matches) > 0 {
+ return InvalidSubjectTypeError{
+ error: fmt.Errorf(
+ "subjects of type `%s` are not allowed on relation `%s#%s`; did you mean `%s`?",
+ schema.SourceForAllowedRelation(relationType),
+ relationship.Resource.ObjectType,
+ relationship.Resource.Relation,
+ matches[0].Target,
+ ),
+ relationship: relationship,
+ relationType: relationType,
+ additionalDetails: nil,
+ }
+ }
+
+ return InvalidSubjectTypeError{
+ error: fmt.Errorf(
+ "subjects of type `%s` are not allowed on relation `%s#%s`",
+ schema.SourceForAllowedRelation(relationType),
+ relationship.Resource.ObjectType,
+ relationship.Resource.Relation,
+ ),
+ relationship: relationship,
+ relationType: relationType,
+ additionalDetails: nil,
+ }
+}
+
+// GRPCStatus implements retrieving the gRPC status for the error.
+func (err InvalidSubjectTypeError) GRPCStatus() *status.Status {
+ details := map[string]string{
+ "definition_name": err.relationship.Resource.ObjectType,
+ "relation_name": err.relationship.Resource.Relation,
+ "subject_type": schema.SourceForAllowedRelation(err.relationType),
+ }
+
+ if err.additionalDetails != nil {
+ maps.Copy(details, err.additionalDetails)
+ }
+
+ return spiceerrors.WithCodeAndDetails(
+ err,
+ codes.InvalidArgument,
+ spiceerrors.ForReason(
+ v1.ErrorReason_ERROR_REASON_INVALID_SUBJECT_TYPE,
+ details,
+ ),
+ )
+}
+
+// CannotWriteToPermissionError indicates that a write was attempted on a permission.
+type CannotWriteToPermissionError struct {
+ error
+ rel tuple.Relationship
+}
+
+// NewCannotWriteToPermissionError constructs a new error for attempting to write to a permission.
+func NewCannotWriteToPermissionError(rel tuple.Relationship) CannotWriteToPermissionError {
+ return CannotWriteToPermissionError{
+ error: fmt.Errorf(
+ "cannot write a relationship to permission `%s` under definition `%s`",
+ rel.Resource.Relation,
+ rel.Resource.ObjectType,
+ ),
+ rel: rel,
+ }
+}
+
+// GRPCStatus implements retrieving the gRPC status for the error.
+func (err CannotWriteToPermissionError) GRPCStatus() *status.Status {
+ return spiceerrors.WithCodeAndDetails(
+ err,
+ codes.InvalidArgument,
+ spiceerrors.ForReason(
+ v1.ErrorReason_ERROR_REASON_CANNOT_UPDATE_PERMISSION,
+ map[string]string{
+ "definition_name": err.rel.Resource.ObjectType,
+ "permission_name": err.rel.Resource.Relation,
+ },
+ ),
+ )
+}
+
+// CaveatNotFoundError indicates that a caveat referenced in a relationship update was not found.
+type CaveatNotFoundError struct {
+ error
+ relationship tuple.Relationship
+}
+
+// NewCaveatNotFoundError constructs a new caveat not found error.
+func NewCaveatNotFoundError(relationship tuple.Relationship) CaveatNotFoundError {
+ return CaveatNotFoundError{
+ error: fmt.Errorf(
+ "the caveat `%s` was not found for relationship `%s`",
+ relationship.OptionalCaveat.CaveatName,
+ tuple.MustString(relationship),
+ ),
+ relationship: relationship,
+ }
+}
+
+// GRPCStatus implements retrieving the gRPC status for the error.
+func (err CaveatNotFoundError) GRPCStatus() *status.Status {
+ return spiceerrors.WithCodeAndDetails(
+ err,
+ codes.FailedPrecondition,
+ spiceerrors.ForReason(
+ v1.ErrorReason_ERROR_REASON_UNKNOWN_CAVEAT,
+ map[string]string{
+ "caveat_name": err.relationship.OptionalCaveat.CaveatName,
+ },
+ ),
+ )
+}