Repository navigation
acllist: reject a new record with no applicable content - #795
Merged
Merged
Conversation
Permission checks live in the per-type apply handlers, so a record whose content reaches none of them was applied without checking its author: an unset oneof or unknown content type fell through applyChangeContent's default, and an AclData with no content values looped zero times. The ErrEmptyAclRecordData guard never ran on live paths, since both unmarshal paths always set Model. Reject both at admission only (ValidateRawRecord and the builder's preflight). A record already in the log was accepted by the network, and a content type added later reaches old clients the same way, so build, migration and sync ingest keep applying it as a no-op whatever the verifier. GO-7544
Coverage provided by https://github.com/seriousben/go-patch-cover-action |
A permissionChanges value checks its author per change, so one with no changes reached its handler and checked nothing, like the no-content records. ValidateAclData now rejects it at admission; stored ones still replay. RevokeAllInvites returns early when there is nothing to revoke instead of building a record the preflight now refuses, so a retry after the revocation already landed still succeeds. GO-7544
A caller that drops the changes members already have may be left with none, e.g. retrying a change that already landed. Building that record now fails admission for carrying no content, so return early instead. GO-7544
requilence
marked this pull request as ready for review
September 29, 2026 09:17
cheggaaa
approved these changes
Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
ACL permission checks run inside the per-content-type apply handlers. A record whose content reaches none of them was applied without any check on its author:
applyChangeContent'sdefaultand returned nil;AclDatawith no content values (emptyData, or only unknown fields) looped zero times;permissionChangesvalue with no changes reached its handler, which checks the author per change, so it checked nothing.The existing
ErrEmptyAclRecordDataguard never runs on live paths: bothUnmarshallandUnmarshallWithIdalways setModel.Fix
Reject both cases at admission only:
ValidateRawRecord(used by the coordinator before handing a record to consensus) and the record builder's preflight. Both now use a dedicated admission validator.Everything that replays records already in the log stays lenient, whatever the verifier:
BuildAclListWithIdentity(clients, and node stats / anytype-heart paths that build withValidateFull)aclmigratorre-adds records viaAddRawRecordswithValidateFull)AddRawRecord)A record already in the log was accepted by the network, and a content type added in a later release reaches old clients the same way, so failing there would stop the ACL at that record.
Compatibility
BuildBatchRequestwith an empty payload now fails locally withErrNoAclContentinstead of sending an empty record.RevokeAllInvitestherefore returns early when there is nothing to revoke (it previously sent an empty record), so a retry after the revocation already landed still succeeds. LikewiseChangePermissionswith no changes (anytype-heart drops changes a member already has, so a retried change can arrive empty) returns without sending.Tests
TestAclList_ValidateRawRecordRejectsNoApplicableContent: all four shapes rejected at admission.TestAclList_StoredNoApplicableContentStillBuilds: the same shapes, once stored, still ingest, rebuild, accept new owner records on top, and migrate into a fresh list, under validating and non-validating verifiers.TestAclList_ValidateRawRecordRejectsMixedContent: a valid change does not carry an inapplicable one past admission in either order, andafterValidnever runs.TestAclRecordBuilder_EmptyBatchRequest,TestAclSpaceClient_RevokeAllInvites,TestAclSpaceClient_ChangePermissionsWithoutChanges.go test ./...passes.Linear: GO-7544