@@ -38,11 +38,11 @@ func TestEnsureDefaultRolePermissions_SeedsEmptyRBACAtomically(t *testing.T) {
3838}
3939
4040func TestRBACDefaultsInitializedEntry_UsesScopedAggregate (t * testing.T ) {
41- server := rbacDefaultsInitializedEntry (ScopeServer , "" , serverRBACDefaultsVersion )
41+ server := rbacDefaultsInitializedEntry (ScopeServer , "" , serverRBACDefaultsVersion , 17 )
4242 if want := events .RBACServerAggregate ().Subject (events .EventRBACDefaultsInitialized ); server .Subject != want {
4343 t .Fatalf ("server marker subject = %q, want %q" , server .Subject , want )
4444 }
45- room := rbacDefaultsInitializedEntry (ScopeRoom , "Rabc123" , roomRBACDefaultsVersion )
45+ room := rbacDefaultsInitializedEntry (ScopeRoom , "Rabc123" , roomRBACDefaultsVersion , 0 )
4646 if want := events .RBACScopedAggregate ("Rabc123" ).Subject (events .EventRBACDefaultsInitialized ); room .Subject != want {
4747 t .Fatalf ("room marker subject = %q, want %q" , room .Subject , want )
4848 }
@@ -79,10 +79,10 @@ func TestRBACDefaultsVersionAdvance_DoesNotReapplyDefaults(t *testing.T) {
7979 core := newRBACDefaultsTestCore (t , harness )
8080 ctx := testContext (t )
8181
82- if err := core .ensureRBACDefaultsInitialized (ctx , ScopeServer , "" , 1 , false , defaultRBACDecisions ()); err != nil {
82+ if err := core .ensureRBACDefaultsInitialized (ctx , ScopeServer , "" , 1 , rbacDefaultsAdoptOnly , defaultRBACDecisions (), 0 ); err != nil {
8383 t .Fatalf ("write version 1 marker: %v" , err )
8484 }
85- if err := core .ensureRBACDefaultsInitialized (ctx , ScopeServer , "" , 2 , true , defaultRBACDecisions ()); err != nil {
85+ if err := core .ensureRBACDefaultsInitialized (ctx , ScopeServer , "" , 2 , rbacDefaultsSeedWhenEmpty , defaultRBACDecisions (), 0 ); err != nil {
8686 t .Fatalf ("advance to version 2: %v" , err )
8787 }
8888
@@ -121,6 +121,86 @@ func TestSeedDefaultChannelRoomPermissions_MarkerPreservesClear(t *testing.T) {
121121 }
122122}
123123
124+ func TestSeedDefaultChannelRoomPermissions_FillsMissingDefaultsAlongsideExistingDecision (t * testing.T ) {
125+ harness := newTestEventHarness (t )
126+ core := newRBACDefaultsTestCore (t , harness )
127+ ctx := testContext (t )
128+ roomID := "Rpartial"
129+
130+ if err := core .DenyRoomPermission (ctx , SystemActorID , roomID , RoleEveryone , PermMessageReact ); err != nil {
131+ t .Fatalf ("DenyRoomPermission unrelated override: %v" , err )
132+ }
133+ if err := core .SeedDefaultChannelRoomPermissions (ctx , roomID , AnnouncementsRoomName ); err != nil {
134+ t .Fatalf ("SeedDefaultChannelRoomPermissions: %v" , err )
135+ }
136+
137+ if got := core .RBAC .GetDecision (ScopeRoom , roomID , RoleEveryone , PermMessageReact ); got != DecisionDeny {
138+ t .Fatalf ("existing unrelated decision = %s, want %s" , got , DecisionDeny )
139+ }
140+ if got := core .RBAC .GetDecision (ScopeRoom , roomID , RoleEveryone , PermMessagePost ); got != DecisionDeny {
141+ t .Fatalf ("missing announcements default = %s, want %s" , got , DecisionDeny )
142+ }
143+ }
144+
145+ func TestSeedDefaultChannelRoomPermissions_PreservesExistingSameKeyDecision (t * testing.T ) {
146+ harness := newTestEventHarness (t )
147+ core := newRBACDefaultsTestCore (t , harness )
148+ ctx := testContext (t )
149+ roomID := "Roverride"
150+
151+ if err := core .GrantRoomPermission (ctx , SystemActorID , roomID , RoleEveryone , PermMessagePost ); err != nil {
152+ t .Fatalf ("GrantRoomPermission override: %v" , err )
153+ }
154+ if err := core .SeedDefaultChannelRoomPermissions (ctx , roomID , AnnouncementsRoomName ); err != nil {
155+ t .Fatalf ("SeedDefaultChannelRoomPermissions: %v" , err )
156+ }
157+
158+ if got := core .RBAC .GetDecision (ScopeRoom , roomID , RoleEveryone , PermMessagePost ); got != DecisionAllow {
159+ t .Fatalf ("same-key decision = %s, want preserved %s" , got , DecisionAllow )
160+ }
161+ }
162+
163+ func TestEnsureDefaultChannelRoomPermissions_RecoversPostCutoffRoomWithExistingDecision (t * testing.T ) {
164+ core , _ := setupTestCore (t )
165+ ctx := testContext (t )
166+ roomID := "Rpostcutoff"
167+ roomEvent := newEvent (SystemActorID , & corev1.Event {Event : & corev1.Event_RoomCreated {
168+ RoomCreated : & corev1.RoomCreatedEvent {
169+ RoomId : roomID ,
170+ Kind : corev1 .RoomKind_ROOM_KIND_CHANNEL ,
171+ Name : AnnouncementsRoomName ,
172+ },
173+ }})
174+ filterSeq , err := core .EventPublisher .LastSubjectSeq (ctx , events .RoomSubjectFilter ())
175+ if err != nil {
176+ t .Fatalf ("read room tail: %v" , err )
177+ }
178+ roomSubject := events .RoomAggregate (roomID ).SubjectFor (roomEvent )
179+ roomSeq , err := core .EventPublisher .AppendAtFilter (ctx , roomSubject , roomEvent , events .RoomSubjectFilter (), filterSeq )
180+ if err != nil {
181+ t .Fatalf ("append post-cutoff room: %v" , err )
182+ }
183+ if err := core .RoomDirectoryProjector .WaitFor (ctx , events .SubjectPosition (roomSubject , roomSeq )); err != nil {
184+ t .Fatalf ("wait for post-cutoff room: %v" , err )
185+ }
186+ if err := core .DenyRoomPermission (ctx , SystemActorID , roomID , RoleEveryone , PermMessageReact ); err != nil {
187+ t .Fatalf ("write unrelated partial decision: %v" , err )
188+ }
189+
190+ if err := core .EnsureDefaultChannelRoomPermissions (ctx ); err != nil {
191+ t .Fatalf ("EnsureDefaultChannelRoomPermissions: %v" , err )
192+ }
193+ if got := core .RBAC .GetDecision (ScopeRoom , roomID , RoleEveryone , PermMessageReact ); got != DecisionDeny {
194+ t .Fatalf ("existing unrelated decision = %s, want %s" , got , DecisionDeny )
195+ }
196+ if got := core .RBAC .GetDecision (ScopeRoom , roomID , RoleEveryone , PermMessagePost ); got != DecisionDeny {
197+ t .Fatalf ("recovered announcements default = %s, want %s" , got , DecisionDeny )
198+ }
199+ if got := core .RBAC .DefaultsVersion (ScopeRoom , roomID ); got != roomRBACDefaultsVersion {
200+ t .Fatalf ("room defaults version = %d, want %d" , got , roomRBACDefaultsVersion )
201+ }
202+ }
203+
124204func TestExistingRoomAdoption_PreservesCompletelyClearedScope (t * testing.T ) {
125205 harness := newTestEventHarness (t )
126206 core := newRBACDefaultsTestCore (t , harness )
@@ -138,8 +218,9 @@ func TestExistingRoomAdoption_PreservesCompletelyClearedScope(t *testing.T) {
138218 ScopeRoom ,
139219 roomID ,
140220 roomRBACDefaultsVersion ,
141- false ,
221+ rbacDefaultsAdoptOnly ,
142222 defaultChannelRoomDecisions (roomID , AnnouncementsRoomName ),
223+ 0 ,
143224 ); err != nil {
144225 t .Fatalf ("adopt existing room: %v" , err )
145226 }
@@ -165,18 +246,40 @@ func TestRoomDefaultsRolloutBoundaryUsesCreationSequence(t *testing.T) {
165246 }
166247
167248 applyRoomCreated ("Rbefore" , 10 )
168- marker := rbacDefaultsInitializedEntry (ScopeServer , "" , serverRBACDefaultsVersion )
169- if err := core .RBAC .Apply (marker .Event , 20 ); err != nil {
249+ applyRoomCreated ("Rbetween" , 30 )
250+ marker := rbacDefaultsInitializedEntry (ScopeServer , "" , serverRBACDefaultsVersion , 20 )
251+ if err := core .RBAC .Apply (marker .Event , 40 ); err != nil {
170252 t .Fatalf ("apply server marker: %v" , err )
171253 }
172- applyRoomCreated ("Rafter" , 30 )
173254
174- markerSeq := core .RBAC .DefaultsInitializedSeq (ScopeServer , "" )
175- if core .shouldSeedUnmarkedRoom ("Rbefore" , markerSeq ) {
176- t .Fatal ("room created before the rollout marker would receive defaults" )
255+ cutoff := core .RBAC .ServerDefaultsRoomStreamCutoff ()
256+ if core .shouldRecoverUnmarkedRoom ("Rbefore" , true , cutoff ) {
257+ t .Fatal ("room created before the room cutoff would receive defaults" )
258+ }
259+ if ! core .shouldRecoverUnmarkedRoom ("Rbetween" , true , cutoff ) {
260+ t .Fatal ("room created after the cutoff but before the server marker would not recover defaults" )
261+ }
262+ }
263+
264+ func TestEnsureDefaultRolePermissions_PersistsRoomStreamCutoff (t * testing.T ) {
265+ harness := newTestEventHarness (t )
266+ core := newRBACDefaultsTestCore (t , harness )
267+ ctx := testContext (t )
268+ roomID := "Rcutoff"
269+ roomEvent := newEvent (SystemActorID , & corev1.Event {Event : & corev1.Event_RoomCreated {
270+ RoomCreated : & corev1.RoomCreatedEvent {RoomId : roomID , Kind : corev1 .RoomKind_ROOM_KIND_CHANNEL },
271+ }})
272+ roomSubject := events .RoomAggregate (roomID ).SubjectFor (roomEvent )
273+ roomSeq , err := harness .publisher .AppendAtFilter (ctx , roomSubject , roomEvent , events .RoomSubjectFilter (), 0 )
274+ if err != nil {
275+ t .Fatalf ("append room creation: %v" , err )
276+ }
277+
278+ if err := core .EnsureDefaultRolePermissions (ctx ); err != nil {
279+ t .Fatalf ("EnsureDefaultRolePermissions: %v" , err )
177280 }
178- if ! core .shouldSeedUnmarkedRoom ( "Rafter" , markerSeq ) {
179- t .Fatal ("room created after the rollout marker would not receive defaults" )
281+ if got := core .RBAC . ServerDefaultsRoomStreamCutoff (); got != roomSeq {
282+ t .Fatalf ("room stream cutoff = %d, want %d" , got , roomSeq )
180283 }
181284}
182285
0 commit comments