@@ -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"
@@ -188,6 +190,11 @@ func ValidateOneRelationship(
188190 return NewCannotWriteToPermissionError (rel )
189191 }
190192
193+ // Validate if the resource, relation or subject is deprecated
194+ if err := checkForDeprecatedRelationsAndObjects (rel , namespaceMap ); err != nil {
195+ return err
196+ }
197+
191198 // Validate the subject against the allowed relation(s).
192199 var caveat * core.AllowedCaveat
193200 if rel .OptionalCaveat != nil {
@@ -277,3 +284,106 @@ func hasNonEmptyCaveatContext(relationship tuple.Relationship) bool {
277284 relationship .OptionalCaveat .Context != nil &&
278285 len (relationship .OptionalCaveat .Context .GetFields ()) > 0
279286}
287+
288+ func checkForDeprecatedRelationsAndObjects (rel tuple.Relationship , nsMap map [string ]* schema.Definition ) error {
289+ // Validate if the resource relation is deprecated
290+ resource := nsMap [rel .Resource .ObjectType ]
291+ relDef , ok := resource .GetRelation (rel .Resource .Relation )
292+ if relDef .Deprecation != nil && relDef .Deprecation .DeprecationType != core .DeprecationType_DEPRECATED_TYPE_UNSPECIFIED && ok {
293+ switch relDef .Deprecation .DeprecationType {
294+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
295+ log .Warn ().
296+ Str ("namespace" , rel .Resource .ObjectType ).
297+ Str ("relation" , rel .Resource .Relation ).
298+ Str ("comments" , relDef .Deprecation .Comments ).
299+ Msg ("write to deprecated relation" )
300+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
301+ return shared .NewDeprecationError (rel .Resource .ObjectType , rel .Resource .Relation , relDef .Deprecation .Comments )
302+ }
303+ }
304+
305+ // Validate if the resource namespace is deprecated
306+ resourceNS := resource .Namespace ()
307+ if resourceNS .Deprecation != nil && resourceNS .Deprecation .DeprecationType != core .DeprecationType_DEPRECATED_TYPE_UNSPECIFIED {
308+ switch resourceNS .Deprecation .DeprecationType {
309+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
310+ log .Warn ().
311+ Str ("namespace" , rel .Resource .ObjectType ).
312+ Str ("comments" , resourceNS .Deprecation .Comments ).
313+ Msg ("write to deprecated object" )
314+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
315+ return shared .NewDeprecationError (rel .Resource .ObjectType , "" , resourceNS .Deprecation .Comments )
316+ }
317+ }
318+
319+ // Validate if the subject namespace is deprecated
320+ subject := nsMap [rel .Subject .ObjectType ]
321+ subjectNS := subject .Namespace ()
322+ if subjectNS .Deprecation != nil &&
323+ subjectNS .Deprecation .DeprecationType != core .DeprecationType_DEPRECATED_TYPE_UNSPECIFIED {
324+ switch subjectNS .Deprecation .DeprecationType {
325+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
326+ log .Warn ().
327+ Str ("namespace" , rel .Subject .ObjectType ).
328+ Str ("comments" , subjectNS .Deprecation .Comments ).
329+ Msg ("write to deprecated object" )
330+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
331+ return shared .NewDeprecationError (rel .Subject .ObjectType , "" , subjectNS .Deprecation .Comments )
332+ }
333+ }
334+ // iterate over the allowed relations in the resource definition
335+ // and see whether the concrete subject we are writing matches an
336+ // entry that has a non-nil deprecation
337+ for _ , allowed := range relDef .TypeInformation .AllowedDirectRelations {
338+ // check namespace
339+ if allowed .Namespace != rel .Subject .ObjectType {
340+ continue
341+ }
342+
343+ // Check if both relations/wildcards match
344+ switch w := allowed .RelationOrWildcard .(type ) {
345+ case * core.AllowedRelation_Relation :
346+ if w .Relation != rel .Subject .Relation {
347+ continue
348+ }
349+ // If it is a match, check the deprecation
350+ if dep := allowed .RequiredDeprecation ; dep != nil &&
351+ dep .DeprecationType != core .DeprecationType_DEPRECATED_TYPE_UNSPECIFIED {
352+ switch dep .DeprecationType {
353+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
354+ log .Warn ().
355+ Str ("namespace" , rel .Resource .ObjectType ).
356+ Str ("comments" , dep .Comments ).
357+ Msg ("write to deprecated relation" )
358+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
359+ return shared .NewDeprecationError (
360+ rel .Subject .ObjectType ,
361+ "" ,
362+ dep .Comments ,
363+ )
364+ }
365+ }
366+ case * core.AllowedRelation_PublicWildcard_ :
367+ if rel .Subject .ObjectID != tuple .PublicWildcard {
368+ continue
369+ }
370+ if dep := allowed .RequiredDeprecation ; dep != nil &&
371+ dep .DeprecationType != core .DeprecationType_DEPRECATED_TYPE_UNSPECIFIED {
372+ switch dep .DeprecationType {
373+ case core .DeprecationType_DEPRECATED_TYPE_WARNING :
374+ log .Warn ().
375+ Str ("namespace" , rel .Resource .ObjectType ).
376+ Str ("comments" , dep .Comments ).
377+ Msg ("write to deprecated wildcard relation" )
378+ case core .DeprecationType_DEPRECATED_TYPE_ERROR :
379+ return shared .NewDeprecationError (
380+ rel .Subject .ObjectType ,
381+ "*" ,
382+ dep .Comments ,
383+ )
384+ }
385+ }
386+ }
387+ }
388+ return nil
389+ }
0 commit comments