@@ -3,7 +3,9 @@ package relationships
33import (
44 "context"
55
6+ log "github.com/authzed/spicedb/internal/logging"
67 "github.com/authzed/spicedb/internal/namespace"
8+ "github.com/authzed/spicedb/internal/services/shared"
79 "github.com/authzed/spicedb/pkg/caveats"
810 caveattypes "github.com/authzed/spicedb/pkg/caveats/types"
911 "github.com/authzed/spicedb/pkg/datastore"
@@ -34,6 +36,19 @@ func ValidateRelationshipUpdates(
3436 return err
3537 }
3638
39+ ts := schema .NewTypeSystem (schema .ResolverForDatastoreReader (reader ))
40+
41+ // check if the relation is deprecated for create or touch operations
42+ var relsToCheck []tuple.Relationship
43+ for _ , update := range updates {
44+ if update .Operation == tuple .UpdateOperationTouch || update .Operation == tuple .UpdateOperationCreate {
45+ relsToCheck = append (relsToCheck , update .Relationship )
46+ }
47+ }
48+ if err := CheckDeprecationsOnRelationships (ctx , relsToCheck , ts ); err != nil {
49+ return err
50+ }
51+
3752 // Validate each updates's types.
3853 for _ , update := range updates {
3954 option := ValidateRelationshipForCreateOrTouch
@@ -71,6 +86,13 @@ func ValidateRelationshipsForCreateOrTouch(
7186 return err
7287 }
7388
89+ ts := schema .NewTypeSystem (schema .ResolverForDatastoreReader (reader ))
90+
91+ // Validate if the resource, relation or subject is deprecated
92+ if err := CheckDeprecationsOnRelationships (ctx , rels , ts ); err != nil {
93+ return err
94+ }
95+
7496 // Validate each relationship's types.
7597 for _ , rel := range rels {
7698 if err := ValidateOneRelationship (
@@ -277,3 +299,104 @@ func hasNonEmptyCaveatContext(relationship tuple.Relationship) bool {
277299 relationship .OptionalCaveat .Context != nil &&
278300 len (relationship .OptionalCaveat .Context .GetFields ()) > 0
279301}
302+
303+ func CheckDeprecationsOnRelationships (
304+ ctx context.Context ,
305+ relationships []tuple.Relationship ,
306+ ts * schema.TypeSystem ,
307+ ) error {
308+ for _ , rel := range relationships {
309+ if err := checkForDeprecatedRelationsAndObjects (ctx , rel , ts ); err != nil {
310+ return err
311+ }
312+ }
313+ return nil
314+ }
315+
316+ func checkForDeprecatedRelationsAndObjects (ctx context.Context , rel tuple.Relationship , ts * schema.TypeSystem ) error {
317+ // Validate if the resource relation is deprecated
318+ relDep , ok , err := ts .GetDeprecationForRelation (ctx , rel .Resource .ObjectType , rel .Resource .Relation )
319+ if err != nil {
320+ return err
321+ }
322+ if ok {
323+ switch relDep .DeprecationType {
324+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
325+ log .Warn ().
326+ Str ("namespace" , rel .Resource .ObjectType ).
327+ Str ("relation" , rel .Resource .Relation ).
328+ Str ("comments" , relDep .Comments ).
329+ Msg ("write to deprecated relation" )
330+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
331+ return shared .NewDeprecationError (rel .Resource .ObjectType , rel .Resource .Relation , relDep .Comments )
332+ }
333+ }
334+
335+ // Validate if the resource namespace is deprecated
336+ resDep , ok , err := ts .GetDeprecationForNamespace (ctx , rel .Resource .ObjectType )
337+ if err != nil {
338+ return err
339+ }
340+ if ok {
341+ switch resDep .DeprecationType {
342+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
343+ log .Warn ().
344+ Str ("namespace" , rel .Resource .ObjectType ).
345+ Str ("comments" , resDep .Comments ).
346+ Msg ("write to deprecated object" )
347+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
348+ return shared .NewDeprecationError (rel .Resource .ObjectType , "" , resDep .Comments )
349+ }
350+ }
351+
352+ // Validate if the subject namespace is deprecated
353+ subDep , ok , err := ts .GetDeprecationForNamespace (ctx , rel .Subject .ObjectType )
354+ if err != nil {
355+ return err
356+ }
357+ if ok {
358+ switch subDep .DeprecationType {
359+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
360+ log .Warn ().
361+ Str ("namespace" , rel .Subject .ObjectType ).
362+ Str ("comments" , subDep .Comments ).
363+ Msg ("write to deprecated object" )
364+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
365+ return shared .NewDeprecationError (rel .Subject .ObjectType , "" , subDep .Comments )
366+ }
367+ }
368+
369+ // check deprecation for allowed relation types
370+ dep , ok , err := ts .GetDeprecationForAllowedRelation (
371+ ctx ,
372+ rel .Resource .ObjectType ,
373+ rel .Resource .Relation ,
374+ rel .Subject .ObjectType ,
375+ rel .Subject .Relation ,
376+ rel .Subject .ObjectID == tuple .PublicWildcard ,
377+ )
378+ if err != nil {
379+ return err
380+ }
381+
382+ errMsg := ""
383+ if rel .Subject .ObjectID == tuple .PublicWildcard {
384+ errMsg = tuple .PublicWildcard
385+ }
386+
387+ if ok {
388+ switch dep .DeprecationType {
389+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
390+ log .Warn ().
391+ Str ("namespace" , rel .Resource .ObjectType ).
392+ Str ("comments" , dep .Comments ).
393+ Msg ("write to deprecated relation" )
394+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
395+ return shared .NewDeprecationError (
396+ rel .Subject .ObjectType ,
397+ errMsg ,
398+ dep .Comments )
399+ }
400+ }
401+ return nil
402+ }
0 commit comments