From ebb14ac3cb3c1a44aa9b65f1a79055e238f8d233 Mon Sep 17 00:00:00 2001 From: BenSimpson Date: Tue, 12 Aug 2025 12:54:39 +1200 Subject: [PATCH] fix: apply correct logic to consistency --- SpiceDb/Api/SpiceDbPermissions.cs | 100 +++++++----------------------- SpiceDb/Enum/CacheFreshness.cs | 3 +- 2 files changed, 23 insertions(+), 80 deletions(-) diff --git a/SpiceDb/Api/SpiceDbPermissions.cs b/SpiceDb/Api/SpiceDbPermissions.cs index 0cde97f..12c892e 100644 --- a/SpiceDb/Api/SpiceDbPermissions.cs +++ b/SpiceDb/Api/SpiceDbPermissions.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Authzed.Api.V1; using Google.Protobuf.Collections; using Grpc.Core; @@ -32,21 +31,12 @@ public async Task> GetResourcePermissionsAsync(string resourceType, { LookupResourcesRequest req = new LookupResourcesRequest { - Consistency = new Authzed.Api.V1.Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), Permission = permission, ResourceObjectType = resourceType, Subject = new SubjectReference { Object = new ObjectReference { ObjectType = subjectType, ObjectId = subjectId } } }; - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - //Server streaming call, reads messages streamed from the service using var call = _acl!.LookupResources(req); @@ -68,20 +58,11 @@ public async Task> GetResourcePermissionsAsync(string resourceType, { var req = new ExpandPermissionTreeRequest { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), Permission = permission, Resource = new ObjectReference { ObjectType = resourceType, ObjectId = resourceId } }; - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - return await _acl!.ExpandPermissionTreeAsync(req); } @@ -96,22 +77,13 @@ public async Task CheckPermissionAsync(string resourceType, { var req = new CheckPermissionRequest { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), Permission = permission, Resource = new ObjectReference { ObjectType = resourceType, ObjectId = resourceId }, Subject = new SubjectReference { Object = new ObjectReference { ObjectType = subjectType, ObjectId = subjectId } }, Context = context?.ToStruct() }; - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - var call = await _acl!.CheckPermissionAsync(req); return new PermissionResponse @@ -131,20 +103,11 @@ public async Task CheckPermissionAsync(string resourceType, { var req = new CheckBulkPermissionsRequest() { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), }; req.Items.AddRange(items); - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - var call = await _acl!.CheckBulkPermissionsAsync(req); if (call == null) @@ -189,23 +152,14 @@ public async Task CheckPermissionAsync(string resourceType, { LookupSubjectsRequest req = new LookupSubjectsRequest { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), Resource = new ObjectReference { ObjectType = resourceType, ObjectId = resourceId }, Permission = permission, SubjectObjectType = subjectType, OptionalSubjectRelation = optionalSubjectRelation, Context = context?.ToStruct() }; - - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - + using var call = _acl!.LookupSubjects(req); await foreach (var resp in call.ResponseStream.ReadAllAsync()) @@ -251,7 +205,7 @@ public async Task CheckPermissionAsync(string resourceType, { LookupResourcesRequest req = new LookupResourcesRequest { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), ResourceObjectType = resourceType, Permission = permission, Subject = new SubjectReference @@ -262,18 +216,8 @@ public async Task CheckPermissionAsync(string resourceType, Context = context?.ToStruct() }; - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } - using var call = _acl!.LookupResources(req); - await foreach (var resp in call.ResponseStream.ReadAllAsync()) { if (resp is null) continue; @@ -310,7 +254,7 @@ public async Task CheckPermissionAsync(string resourceType, ReadRelationshipsRequest req = new ReadRelationshipsRequest() { - Consistency = new Consistency { MinimizeLatency = true, AtExactSnapshot = zedToken }, + Consistency = CreateConsistency(zedToken, cacheFreshness), RelationshipFilter = CreateRelationshipFilter(resourceType, optionalResourceId, optionalRelation, optionalSubjectType, optionalSubjectId, optionalSubjectRelation), OptionalLimit = limit != null ? Math.Clamp((uint)limit, 0, 1000) : 0, OptionalCursor = cursor is null ? null : new Authzed.Api.V1.Cursor @@ -318,15 +262,6 @@ public async Task CheckPermissionAsync(string resourceType, Token = cursor.Token } }; - - if (cacheFreshness == CacheFreshness.AtLeastAsFreshAs) - { - req.Consistency.AtLeastAsFresh = zedToken; - } - else if (cacheFreshness == CacheFreshness.MustRefresh || zedToken == null) - { - req.Consistency.FullyConsistent = true; - } using var call = _acl!.ReadRelationships(req); @@ -355,7 +290,6 @@ public async Task CheckPermissionAsync(string resourceType, } } - public bool UpdateRelationships(ref RepeatedField updateCollection, RelationshipUpdate updateItem, bool addOrDelete = true) { if (addOrDelete) @@ -419,8 +353,7 @@ public RelationshipUpdate GetRelationshipUpdate(string resourceType, string reso } }; } - - + public async Task WriteRelationshipsAsync(RepeatedField updateCollection, RepeatedField? optionalPreconditions = null) { WriteRelationshipsRequest req = new WriteRelationshipsRequest() @@ -432,8 +365,6 @@ public async Task WriteRelationshipsAsync(RepeatedFi return await _acl!.WriteRelationshipsAsync(req); } - - public async Task UpdateRelationshipAsync(string resourceType, string resourceId, string relation, string subjectType, string subjectId, string optionalSubjectRelation = "", RelationshipUpdate.Types.Operation operation = RelationshipUpdate.Types.Operation.Touch, Caveat? caveat = null) @@ -495,4 +426,15 @@ private static Authzed.Api.V1.RelationshipFilter CreateRelationshipFilter(string return filter; } + + private static Consistency CreateConsistency(ZedToken? zedToken, CacheFreshness cacheFreshness) => + (cacheFreshness, zedToken) switch + { + (CacheFreshness.AnyFreshness, _) => new Consistency { MinimizeLatency = true }, + (CacheFreshness.MustRefresh, _) => new Consistency { FullyConsistent = true}, + (CacheFreshness.AtLeastAsFreshAs, not null) => new Consistency { AtLeastAsFresh = zedToken }, + (CacheFreshness.AtExactSnapshot, not null) => new Consistency { AtExactSnapshot = zedToken }, + (CacheFreshness.AtExactSnapshot or CacheFreshness.AtLeastAsFreshAs, null) => throw new ArgumentException("ZedToken must be provided when using AtExactSnapshot or AtLeastAsFreshAs"), + _ => throw new ArgumentOutOfRangeException(nameof(cacheFreshness), cacheFreshness, "Invalid cache freshness value") + }; } diff --git a/SpiceDb/Enum/CacheFreshness.cs b/SpiceDb/Enum/CacheFreshness.cs index d560a67..8edb1db 100644 --- a/SpiceDb/Enum/CacheFreshness.cs +++ b/SpiceDb/Enum/CacheFreshness.cs @@ -4,5 +4,6 @@ public enum CacheFreshness { AnyFreshness, AtLeastAsFreshAs, - MustRefresh + MustRefresh, + AtExactSnapshot }