diff --git a/SpiceDb/Api/SpiceDbPermissions.cs b/SpiceDb/Api/SpiceDbPermissions.cs index eedd2a2..c055a9b 100644 --- a/SpiceDb/Api/SpiceDbPermissions.cs +++ b/SpiceDb/Api/SpiceDbPermissions.cs @@ -1,6 +1,7 @@ using Authzed.Api.V1; using Google.Protobuf; using Google.Protobuf.Collections; +using Google.Protobuf.WellKnownTypes; using Grpc.Core; using SpiceDb.Enum; using SpiceDb.Models; @@ -396,7 +397,7 @@ public bool UpdateRelationships(ref RepeatedField updateColl public RelationshipUpdate GetRelationshipUpdate(string resourceType, string resourceId, string relation, string subjectType, string subjectId, string optionalSubjectRelation = "", - RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch) + RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch, Caveat? caveat = null) { return new RelationshipUpdate { @@ -406,6 +407,7 @@ public RelationshipUpdate GetRelationshipUpdate(string resourceType, string reso Resource = new ObjectReference { ObjectType = resourceType, ObjectId = resourceId }, Relation = relation, Subject = new SubjectReference { Object = new ObjectReference { ObjectType = subjectType, ObjectId = subjectId }, OptionalRelation = optionalSubjectRelation }, + OptionalCaveat = GetCaveat(caveat) } }; } @@ -426,21 +428,21 @@ public async Task WriteRelationshipsAsync(RepeatedFi public async Task UpdateRelationshipAsync(string resourceType, string resourceId, string relation, string subjectType, string subjectId, string optionalSubjectRelation = "", - RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch) + RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch, Caveat? caveat = null) { - return await UpdateRelationshipsAsync(resourceType, resourceId, new[] { relation }, subjectType, subjectId, optionalSubjectRelation, operation); + return await UpdateRelationshipsAsync(resourceType, resourceId, new[] { relation }, subjectType, subjectId, optionalSubjectRelation, operation, caveat); } public async Task UpdateRelationshipsAsync(string resourceType, string resourceId, IEnumerable relations, string subjectType, string subjectId, string optionalSubjectRelation = "", - RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch) + RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch, Caveat? caveat = null) { RepeatedField updateCollection = new RepeatedField(); foreach (var relation in relations) { - var updateItem = GetRelationshipUpdate(resourceType, resourceId, relation.ToLowerInvariant(), subjectType, subjectId, optionalSubjectRelation, operation); + var updateItem = GetRelationshipUpdate(resourceType, resourceId, relation.ToLowerInvariant(), subjectType, subjectId, optionalSubjectRelation, operation, caveat); UpdateRelationships(ref updateCollection, updateItem); } @@ -448,4 +450,17 @@ public async Task UpdateRelationshipsAsync(string resourceType, string return resp.WrittenAt; } + protected ContextualizedCaveat? GetCaveat(Caveat? caveat) + { + if (caveat is null) + { + return null; + } + + return new ContextualizedCaveat + { + CaveatName = caveat.Name, + Context = caveat.Context?.ToStruct(), + }; + } } \ No newline at end of file diff --git a/SpiceDb/Models/Relationship.cs b/SpiceDb/Models/Relationship.cs index c76c8f9..f7da306 100644 --- a/SpiceDb/Models/Relationship.cs +++ b/SpiceDb/Models/Relationship.cs @@ -7,6 +7,7 @@ public Relationship(ResourceReference resource, string relation, ResourceReferen Resource = resource; Relation = relation; Subject = subject; + OptionalCaveat = optionalCaveat; if (!string.IsNullOrEmpty(Resource.Relation)) { diff --git a/SpiceDb/SpiceDbClient.cs b/SpiceDb/SpiceDbClient.cs index ec787e6..5b1b65b 100644 --- a/SpiceDb/SpiceDbClient.cs +++ b/SpiceDb/SpiceDbClient.cs @@ -161,7 +161,7 @@ public async IAsyncEnumerable ReadRelationshipsAsync( OptionalCaveat = x.Relationship.OptionalCaveat != null ? new Authzed.Api.V1.ContextualizedCaveat { - CaveatName = x.Relationship.OptionalCaveat.Name, + CaveatName = EnsurePrefix(x.Relationship.OptionalCaveat.Name)!, Context = x.Relationship.OptionalCaveat.Context.ToStruct() } : null @@ -370,7 +370,7 @@ private PermissionRelationshipTree BuildTree(Authzed.Api.V1.PermissionRelationsh var request = relationships.Select(x => new RelationshipUpdate { Relationship = new Relationship( - x.Resource.EnsurePrefix(_prefix), x.Relation, x.Subject.EnsurePrefix(_prefix), x.OptionalCaveat + x.Resource.EnsurePrefix(_prefix), x.Relation, x.Subject.EnsurePrefix(_prefix), EnsureCaveatIsPrefixed(x.OptionalCaveat) ), Operation = RelationshipUpdateOperation.Upsert }).ToList(); @@ -387,7 +387,7 @@ public async Task AddRelationshipAsync(Relationship relation) { return (await _spiceDbCore.Permissions.UpdateRelationshipAsync(EnsurePrefix(relation.Resource.Type)!, relation.Resource.Id, relation.Relation, EnsurePrefix(relation.Subject.Type)!, relation.Subject.Id, - relation.Subject.Relation)) + relation.Subject.Relation, caveat: EnsureCaveatIsPrefixed(relation.OptionalCaveat))) .ToSpiceDbToken()!; } @@ -627,4 +627,15 @@ public async Task ImportSchemaFromStringAsync(string schema) return type.StartsWith(_prefix + "/") ? type : $"{_prefix}/{type}"; } + + private Caveat? EnsureCaveatIsPrefixed(Caveat? caveat) + { + if (caveat is null) + { + return null; + } + + caveat.Name = EnsurePrefix(caveat.Name)!; + return caveat; + } } \ No newline at end of file