feat: add container-specific permissions and immutable flag#272
feat: add container-specific permissions and immutable flag#272flash7777 wants to merge 6 commits into
Conversation
Add two new permission fields to ResourcePermissions: - delete_container (field 21): controls whether containers/directories can be deleted, independent of the file delete permission - move_container (field 22): controls whether containers/directories can be moved or renamed, independent of the file move permission Add immutable field (field 20) to ResourceInfo: - When set, prevents modification, deletion, moving or renaming - For containers, also prevents creation of new children - Existing non-immutable children can still be modified These additions enable DMS use cases such as: - File plan (Aktenplan) structure protection - Retention/legal hold at the resource level - Granular permission control separating file and directory operations The new permission fields are backward compatible: when not explicitly set, implementations should fall back to the existing delete/move permissions for containers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add proposal document explaining the motivation, specification, and backward compatibility for the new delete_container, move_container, and immutable fields. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Context: Why we need thisWe are currently developing an EDMS (Electronic Document Management System) layer on top of OpenCloud/Reva for German municipalities and public administration (Kommunalverwaltungen). In this domain, file plans (Aktenpläne) are a fundamental concept — rigid, hierarchical directory structures (typically 4 levels deep) that must remain stable over years or even decades. Users work within this structure daily: they create, edit, and manage documents, but the structure itself must not be accidentally (or intentionally) altered by regular users. Today, the CS3 permission model offers no way to express this. The The three additions in this proposal — We believe this benefits not just our EDMS project, but any CS3-based deployment where directory structures carry organizational meaning — universities, research institutions, enterprises, and public sector organizations alike. We are happy to contribute the implementation work in Reva (see cs3org/reva#5628) and would appreciate feedback from the community on the proposed API design. |
|
Quick note: The commits mention "Claude" as co-author — this just means we used Claude Code (AI coding assistant) as tooling support during development. The proposal and its rationale are entirely ours, based on real requirements from our EDMS project. Happy to discuss any aspect of it. |
- Add immutable field (20) to ResourceInfo as persistent xattr attribute - Add SetImmutable/UnsetImmutable RPCs to ProviderAPI - Update proposal to clarify distinction between attribute (immutable) and action (SetImmutable), and how it differs from locks and status
|
Hi @flash7777, thanks for the contribution, I can see the idea is genuine even if the text is produced by Claude. I do think this makes very much sense. The only issue I can see in terms of implementations is how can a storage provider honor the immutable flag, for the cases (such as how we deploy Reva at CERN) where users have direct access to the storage. But ok this is kind of an implementation detail, the extended permission model could already be used without implementing the immutable RPCs. |
|
Thanks for the quick feedback! Good point about the immutable flag and direct storage access. You are right — if users can bypass Reva and access the storage directly (e.g. via EOS FUSE mount), an xattr-based immutable flag alone cannot be enforced. A few thoughts:
Would it make sense to split this into two PRs — one for the permission fields only, and a separate one for immutable? That way the permissions can move forward without being blocked by the immutable discussion. |
|
One more thought on the direct-access question: regardless of the enforcement layer, the immutable state has to live somewhere. A separate database or metastore would add complexity and synchronization issues. Storing it as an xattr directly on the resource (as Reva already does for locks, ACLs, etc.) seems like the natural fit. For EOS with FUSE access, the storage driver could map the immutable flag to native EOS attributes (e.g. |
|
I see that the community is growing and more use cases are evolving. I see no disadvantages with this change, so let’s go for it. |
Refine the immutable field comment to distinguish: - File (freeze): final, irreversible, no modification - Container (protect): structure fixed, reversible by managers - Self vs. parent rule: object is immutable if own or parent attribute is set Add immutable-overview.md as reference specification. No structural changes to the proto definition.
|
Pushed a documentation-only update to clarify the immutable semantics based on our EDMS experience. No structural changes to the proto — just refined comments. Key clarifications:
Added |
Add two permission fields to control who may set the immutable attribute, separated by resource type: - set_immutable_file (field 23): freeze files (irreversible) - set_immutable_container (field 24): protect/unprotect containers (reversible by managers) This separation allows roles to grant container protection rights without granting the ability to irreversibly freeze files.
|
Added two permission fields for controlling who may set the immutable attribute:
This follows the same pattern as |
Add xattr-based immutable (freeze/protect) support: Storage: - New xattr: user.oc.immutable - ImmutableState enum: None, Protected (parent), Frozen (self) Node methods: - IsImmutable(): check self attribute - GetImmutableState(): effective state (self or parent) - FreezeFile(): set immutable on file (irreversible) - ProtectContainer(): set immutable on container (reversible) - UnprotectContainer(): remove immutable from container Handler checks (Delete, Move, CreateDir, Upload): - Frozen/protected resources cannot be deleted or moved - Protected containers reject new children and modifications - Frozen files reject overwrite TODO markers for delete_container/move_container (cs3org/cs3apis#272).
Port cs3org/cs3apis#272 via forked go-cs3apis with new fields: - DeleteContainer, MoveContainer (ResourcePermissions fields 21-22) - SetImmutableFile, SetImmutableContainer (fields 23-24) - Immutable (ResourceInfo field 20) Changes: - go.mod: replace cs3org/go-cs3apis with flash7777/go-cs3apis fork - role.go: Editor/SpaceEditor/Manager/Coowner get DeleteContainer and MoveContainer; Manager/Coowner get SetImmutable permissions - decomposedfs.go: replace TODO markers with real DeleteContainer and MoveContainer checks in Delete/Move handlers - grants.go: ACL encoding/decoding for +dc/!dc and +mc/!mc - tests: add DeleteContainer to permission mocks where dirs are deleted Directory Delete/Move now requires explicit DeleteContainer/MoveContainer permission. This is a breaking change — existing roles have been updated.
|
Thanks for the approval @glpatcern! Is there anything else needed before this can be merged? Happy to address any remaining concerns. |
|
Note: after your approval on May 28, we pushed two additional commits on May 30:
Would appreciate a quick look at these additions before merge. The rest is unchanged from what you approved. |
The code references fields from cs3org/cs3apis#272 (DeleteContainer, MoveContainer, SetImmutableFile, SetImmutableContainer, Immutable). These will compile once go-cs3apis is regenerated after cs3apis merge.
Summary
This PR adds container-specific permissions and an immutable (freeze) attribute to the CS3 storage provider API.
New fields in
ResourcePermissionsdelete_container(field 21): delete permission for containers only, independent of filedeletemove_container(field 22): move/rename permission for containers only, independent of filemoveNew attribute in
ResourceInfoimmutable(field 20): persistent boolean attribute (xattr) — when true, resource cannot be modified/deleted/moved/renamed. For containers, also prevents creation of new children.New RPCs in
ProviderAPISetImmutable: freezes a resource (manager/admin only)UnsetImmutable: unfreezes a resource (manager/admin only)Motivation
We are developing an EDMS layer for German municipalities on top of OpenCloud/Reva. Core requirement: protecting file plan (Aktenplan) directory structures while allowing users to work freely with documents inside them.
The current API cannot express "users may delete files but not directories" —
deleteandmoveapply to both equally. And there is no persistent freeze/immutable concept (locks are temporary).See
docs/proposals/container-permissions-and-immutable.mdfor the full proposal.Note on field 20
Field 20 in
ResourceInfois also targeted by #190 (Status). We have commented there to coordinate. We believeimmutableandstatusserve different purposes (persistent admin attribute vs. transient processing state) and deserve separate fields.Backward compatibility
All changes are additive. When new permission fields are not set, implementations fall back to existing
delete/movebehavior. Existing clients continue to work unchanged.Related