diff --git a/pkg/acl/tree/acltree.go b/pkg/acl/tree/acltree.go index 6b148f36..1fe94285 100644 --- a/pkg/acl/tree/acltree.go +++ b/pkg/acl/tree/acltree.go @@ -15,6 +15,7 @@ import ( type AddResultSummary int var ErrTreeWithoutIdentity = errors.New("acl tree is created without identity") +var ErrHasInvalidChanges = errors.New("the change is invalid") const ( AddResultSummaryNothing AddResultSummary = iota diff --git a/pkg/acl/tree/doctree.go b/pkg/acl/tree/doctree.go index 63933983..e2bc014f 100644 --- a/pkg/acl/tree/doctree.go +++ b/pkg/acl/tree/doctree.go @@ -228,6 +228,10 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges if d.HasChange(ch.Id) { continue } + // if we already added the change to invalid ones + if _, exists := d.tree.invalidChanges[ch.Id]; exists { + return AddResult{}, ErrHasInvalidChanges + } var change *Change change, err = NewFromVerifiedRawChange(ch, d.identityKeys, d.treeBuilder.signingPubKeyDecoder) @@ -329,7 +333,15 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges // as an optimization we could've started from current heads, but I didn't implement that err = d.validator.ValidateTree(d.tree, aclTree) if err != nil { - return AddResult{}, err + // rolling back + for _, ch := range d.tmpChangesBuf { + if _, exists := d.tree.attached[ch.Id]; exists { + delete(d.tree.attached, ch.Id) + } else if _, exists := d.tree.unAttached[ch.Id]; exists { + delete(d.tree.unAttached, ch.Id) + } + } + return AddResult{}, ErrHasInvalidChanges } addResult = AddResult{