Skip to content

feat: go-cs3apis update + immutable attribute + container permissions#676

Open
flash7777 wants to merge 4 commits into
opencloud-eu:mainfrom
flash7777:feature/immutable-decomposedfs
Open

feat: go-cs3apis update + immutable attribute + container permissions#676
flash7777 wants to merge 4 commits into
opencloud-eu:mainfrom
flash7777:feature/immutable-decomposedfs

Conversation

@flash7777

Copy link
Copy Markdown

Summary

Two features + go-cs3apis update in one PR:

1. go-cs3apis update (Jun 2026)

Bumps go-cs3apis to include cs3org/cs3apis#272 and Labels API migration.

Before:  opencloud -> Gateway -> StorageProvider (ProviderAPI.AddLabel)
After:   opencloud -> Gateway -> StorageProvider (LabelsAPI.AddLabel)

StorageProvider registers as LabelsAPIServer. Gateway routes via new LabelsAPIClient.

2. Immutable attribute (freeze/protect)

Persistent xattr (user.oc.immutable) on resources:

  • File (freeze): content fixed, irreversible
  • Container (protect): structure fixed, reversible by managers
  • Self vs parent rule: Frozen / Protected / None

3. Container-specific permissions

DeleteContainer / MoveContainer separate file and directory operations.
SetImmutableFile / SetImmutableContainer control who can freeze/protect.

Changes

  • go.mod: bump go-cs3apis
  • Labels: StorageProvider as LabelsAPIServer, Gateway wiring via pool
  • decomposedfs: immutable xattr, handler checks (Delete/Move/CreateDir/Upload)
  • Node: FreezeFile, ProtectContainer, UnprotectContainer, GetImmutableState
  • Roles: DeleteContainer/MoveContainer on Editor+, SetImmutable on Manager+
  • ACL: +dc/!dc, +mc/!mc, +if/+ic encoding
  • WebDAV: oc:immutable property, D/NV strip
  • GRPC: SetImmutable/UnsetImmutable handlers
  • 21 new tests

Test plan

  • Full build passes
  • 21 new tests pass (node, handler, grants ACL)
  • CI pipeline
  • Labels (favorites) end-to-end
  • Immutable: set on dir, verify children protected

@flash7777

Copy link
Copy Markdown
Author

Note: This PR adds the storage-level infrastructure for immutable resources. Follow-up PRs for the Graph API layer (new LibreGraph actions for container/delete, container/move, immutable/file/set, immutable/container/set) and the web frontend (frozen/protected icons, canBeDeleted/canRename integration) are ready on separate branches and will be submitted after this PR is merged.

@flash7777 flash7777 force-pushed the feature/immutable-decomposedfs branch 3 times, most recently from 8f0f8f7 to 8f0f07b Compare June 13, 2026 16:48
@flash7777

Copy link
Copy Markdown
Author

Update: unit tests added + OpenCloud compatibility note

New commit: role permission tests

Added unit tests verifying that container-specific permissions are correctly assigned to roles:

  • Editor/SpaceEditor: DeleteContainer + MoveContainer (no SetImmutable)
  • Manager/Coowner: all new permissions including SetImmutableFile + SetImmutableContainer
  • Viewer: none of the new permissions
  • SufficientPermissions: Manager >= Editor, Editor < Manager

Required OpenCloud change after merge

After merging this PR, OpenCloud's services/graph/pkg/service/v0/follow.go must be updated because the Labels API moved from provider to labels package:

// Add import:
labels "github.com/cs3org/go-cs3apis/cs3/labels/v1beta1"

// Change (line ~64):
req := &labels.AddLabelRequest{...}    // was: provider.AddLabelRequest

// Change (line ~133):
req := &labels.RemoveLabelRequest{...} // was: provider.RemoveLabelRequest

Without this change, OpenCloud will fail to compile after updating go-cs3apis.

flash added 3 commits June 14, 2026 18:31
Update to the latest go-cs3apis which includes three upstream changes:

1. cs3org/cs3apis#272 — container-specific permissions + immutable RPCs
2. cs3org/cs3apis#273 — OCM share state changes
3. Labels API moved from StorageProvider to cs3/labels/v1beta1

Labels API migration:

  Before:  opencloud -> Gateway -> StorageProvider (ProviderAPI.AddLabel)
  After:   opencloud -> Gateway -> StorageProvider (LabelsAPI.AddLabel)

  The StorageProvider now registers as LabelsAPIServer in addition to
  ProviderAPIServer and SpacesAPIServer. The Gateway routes Labels calls
  to the StorageProvider via a new LabelsAPIClient, using the same
  GRPC connection pool.

Changes:
- go.mod: bump go-cs3apis
- StorageProvider: register as LabelsAPIServer, implement
  AddLabel/RemoveLabel via Storage FS interface
- Gateway: route AddLabel/RemoveLabel to StorageProvider's LabelsAPI
- Pool: add LabelsProviderSelector and GetLabelsProviderServiceClient
- Add SetImmutable/UnsetImmutable to all ProviderAPI implementations
- Regenerate mocks
Add two features to the decomposedfs storage driver:

1. Container-specific permissions (cs3org/cs3apis#272):
   - DeleteContainer/MoveContainer checks in Delete/Move handlers
   - ACL encoding: +dc/!dc, +mc/!mc (with substring collision fix)
   - Roles updated: Editor/Manager/Coowner get DeleteContainer/MoveContainer
   - SetImmutableFile/SetImmutableContainer permissions on Manager/Coowner

2. Immutable attribute (freeze/protect):
   - xattr: user.oc.immutable
   - File (freeze): content fixed, irreversible
   - Container (protect): structure fixed, reversible by managers
   - Self vs parent rule: ImmutableState = Frozen/Protected/None
   - Node methods: FreezeFile, ProtectContainer, UnprotectContainer
   - Storage interface: SetImmutable/UnsetImmutable with permission checks
   - GRPC handlers: storageprovider + gateway pass-through
   - Handler checks: Delete, Move, CreateDir, Upload
   - Stat: ResourceInfo.Immutable + Opaque immutable-state
   - WebDAV: oc:immutable property + D/NV strip from oc:permissions
   - OwnerPermissions/AddPermissions updated

Tests: 21 new (node, handler, grants ACL), all pass.
2 pre-existing failures (UpdateGrant/DenyGrant ACL round-trip).
Verify that new permissions (DeleteContainer, MoveContainer,
SetImmutableFile, SetImmutableContainer) are correctly assigned:
- Editor/SpaceEditor: DeleteContainer + MoveContainer (no SetImmutable)
- Manager/Coowner: all new permissions
- Viewer: none of the new permissions
- SufficientPermissions: Manager >= Editor, Editor < Manager
@flash7777 flash7777 force-pushed the feature/immutable-decomposedfs branch from db0affa to 8fa78d0 Compare June 14, 2026 16:34
flash7777 pushed a commit to flash7777/opencloud that referenced this pull request Jun 14, 2026
…ources

Three new Graph API endpoints on drive items:

  POST   /drives/{driveID}/items/{itemID}/freeze    - freeze a file (irreversible)
  POST   /drives/{driveID}/items/{itemID}/protect   - protect a directory (reversible)
  DELETE /drives/{driveID}/items/{itemID}/protect    - unprotect a directory

Semantics:
- freeze: sets immutable on files, cannot be undone, client must confirm
- protect: sets immutable on directories, can be reversed by managers
- unprotect: removes immutable from directories

Each endpoint validates the resource type (file vs directory) and returns
appropriate errors for type mismatches, permission denied, and not found.

Depends on: opencloud-eu/reva#676 (SetImmutable/UnsetImmutable RPCs)
flash7777 pushed a commit to flash7777/opencloud that referenced this pull request Jun 14, 2026
…ources

Three new Graph API endpoints on drive items:

  POST   /drives/{driveID}/items/{itemID}/freeze    - freeze a file (irreversible)
  POST   /drives/{driveID}/items/{itemID}/protect   - protect a directory (reversible)
  DELETE /drives/{driveID}/items/{itemID}/protect    - unprotect a directory

Semantics:
- freeze: sets immutable on files, cannot be undone, client must confirm
- protect: sets immutable on directories, can be reversed by managers
- unprotect: removes immutable from directories

Each endpoint validates the resource type (file vs directory) and returns
appropriate errors for type mismatches, permission denied, and not found.

Depends on: opencloud-eu/reva#676 (SetImmutable/UnsetImmutable RPCs)
A directory with IsImmutable=true is protected, not frozen.
Only files can be frozen. Previously GetImmutableState returned
ImmutableFrozen for any node with IsImmutable=true regardless of type.

Now:
- File + IsImmutable=true → ImmutableFrozen
- Directory + IsImmutable=true → ImmutableProtected (self-protected)
- Child of immutable parent → ImmutableProtected (inherited)
- Normal → ImmutableNone
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant