Skip to content

Add EXTRA_GROUPS env var for beetle user group membership#239

Merged
pSpitzner merged 10 commits intopSpitzner:mainfrom
djdubd:feature/extra-groups-env-var
Dec 8, 2025
Merged

Add EXTRA_GROUPS env var for beetle user group membership#239
pSpitzner merged 10 commits intopSpitzner:mainfrom
djdubd:feature/extra-groups-env-var

Conversation

@djdubd
Copy link
Contributor

@djdubd djdubd commented Dec 7, 2025

Fixes #234

The web UI cannot delete inbox files owned by groups other than beetle's primary group (gid=1000). This affects setups where download clients create files as root or with different group ownership.

Changes

  • docker/entrypoints/entrypoint_fix_permissions.sh: Parse EXTRA_GROUPS env var and add beetle to specified groups at container startup
  • docker/docker-compose.yaml: Add commented example
  • docs/configuration.md: Document new env var under "Docker Environment Variables"

Usage

environment:
    EXTRA_GROUPS: "nas_shares:1001,media:1002"

Groups are created if they don't exist, then beetle is added. Invalid specs (missing colon, non-numeric/negative GID) are logged and skipped.

Testing

Tested by building the dev container with EXTRA_GROUPS: "nas_shares:2000":

  1. Verified group membership:

    $ docker exec beets-flask id beetle
    uid=1000(beetle) gid=1000(beetle) groups=1000(beetle),2000(nas_shares)
    
  2. Positive test - beetle can delete files owned by root:nas_shares (775 permissions):

    $ docker exec -u beetle beets-flask rm /music/inbox/test-album/test-file.flac
    # SUCCESS
    
  3. Negative test - beetle cannot delete files owned by root:root (as expected):

    $ docker exec -u beetle beets-flask rm /music/inbox/test-album2/test-file2.flac
    rm: can't remove '...': Permission denied
    # EXPECTED
    

This provides users with a container-side solution for the permissions issue, eliminating the need for host-level ACL modifications.

Copilot AI and others added 4 commits December 6, 2025 04:21
Co-authored-by: djdubd <2773193+djdubd@users.noreply.github.com>
Co-authored-by: djdubd <2773193+djdubd@users.noreply.github.com>
Co-authored-by: djdubd <2773193+djdubd@users.noreply.github.com>
Copilot AI review requested due to automatic review settings December 7, 2025 00:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for adding the beetle user to additional groups at container startup, addressing permission issues when managing files owned by groups other than beetle's primary group (GID 1000).

Key Changes:

  • Adds EXTRA_GROUPS environment variable for specifying additional group memberships
  • Implements parsing and validation logic for comma-separated group_name:gid pairs
  • Documents the new feature with usage examples and common use cases

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
docker/entrypoints/entrypoint_fix_permissions.sh Implements parsing of EXTRA_GROUPS env var with validation, group creation, and user membership management
docker/docker-compose.yaml Adds commented example showing how to configure EXTRA_GROUPS
docs/configuration.md Documents the new EXTRA_GROUPS variable with format, examples, and use cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

djdubd and others added 5 commits December 6, 2025 23:05
Add group name validation

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Warn user if named group exists with different gid

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add explicit check for user having existing group membership.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Remove misleading variable example

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Remove incorrect and redundant positive integer check.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Collaborator

@semohr semohr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Highly appreciated.

I left some comments which hopeful allow us to make this more maintainable going forward.


I didn’t follow the initial issue too closely, but I was wondering how this approach compares to docker compose’s built-in group_add option. Are there specific reasons we’re handling it manually here instead of trying to use the buildin feature? I know we are currently also not using the user option properly but maybe now is the time to reevaluate this and maybe also simplify?

@pSpitzner
Copy link
Owner

pSpitzner commented Dec 8, 2025

Thank you for the PR! Highly appreciated.

+1 :)

I was wondering how this approach compares to docker compose’s built-in group_add option. Are there specific reasons we’re handling it manually here instead of trying to use the buildin feature? I know we are currently also not using the user option properly but maybe now is the time to reevaluate this and maybe also simplify?

I agree, using as much of dockers built-ins as possible would be good.
The one limitation I see is that group_add accepts a mixed list of gids or names, but not combination of both per entry.

@semohr
Copy link
Collaborator

semohr commented Dec 8, 2025

I agree, using as much of dockers built-ins as possible would be good.
The one limitation I see is that group_add accepts a mixed list of gids or names, but not combination of both per entry.

Why would you need both per entry? Maybe I'm missing something 🤔

E.g.:

services:
  ubuntu:
    image: ubuntu:latest
    command: tail -f /dev/null
    stdin_open: true
    tty: true
    user: 1000:998
    group_add:
      - 24
      - dialout

The group id and names are resolved properly and the same as on the host:

# in container
> id
uid=1000(ubuntu) gid=998 groups=998,20(dialout),24(cdrom)
# host machine
> id
...,20(dialout),24(cdrom),...

@djdubd
Copy link
Contributor Author

djdubd commented Dec 8, 2025

I don't disagree that it would be better handled using group_add in the compose file. This issue was raised initially because adding groups or specifying the uid and gid in those files didn't affect the beetle user which actually runs the application:

# The container itself runs as root
$ docker exec beets-flask id
uid=0(root) gid=1000(beetle) groups=1000(beetle)

# But the actual application processes run as beetle
$ docker exec beets-flask ps aux | grep uvicorn
beetle    43  0:00 {uvicorn} /usr/local/bin/python3 /usr/local/bin/uvicorn...

# And the beetle user inside the container has no group membership beyond its own
$ docker exec beets-flask id beetle
uid=1000(beetle) gid=1000(beetle) groups=1000(beetle),1000(beetle)

My first proposed solution was to honor the settings chosen in the compose file related to uid and gid. This allows the user to choose.

@pSpitzner proposed adding extra groups to the beetle user, and I agreed that would solve the issue, and at least allow for flexibility accessing and writing files by group membership.

I think this discussion is good, and appreciate you all paying attention to this. I look forward to knowing what the consensus is.

@semohr
Copy link
Collaborator

semohr commented Dec 8, 2025

The main question for me is whether we should drop the custom user-creation steps in the Dockerfile and instead rely on the built-in user and add_group functions. That approach feels cleaner and more maintainable to me.

I understand why the PR is structured the way it is now, but I’m wondering if simplifying things and removing the extra layers might give us a more streamlined solution overall.

Do we think there are any downsides we might run into by switching entirely to the built-in user/group functionality. If not, I’d vote to drop the extra steps. We’re planning a 2.0.0 release in the near future anyway, so this seems like a reasonable change to include.

- Separated group_add into its own entrypoint script (called by fix_permissions one)
- Split group_add logic into two functions
- Removed old Testing parts from Dockerfile and entrypoint
- Improved chown performance on macos
@pSpitzner
Copy link
Owner

We just took another spin at it.
After playing around with the docker native approaches we decided against them. Long story short, it is not trivial to create matching pairs of [group-name + gid]. While possible to set the uid:gid, and even extra gids, the part needed for the initial issue was not possible - Docker only matches the gid numerically, so that you might again end up with inconsistent group-names inside and out. If you add a group via name, it needs to exist already in the container.

@djdubd
Feel free to have a look at the changes we just pushed, and let us know what you think.

Copy link
Contributor Author

@djdubd djdubd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I believe it will add an additional level of flexibility for those with complex requirements due to nested virtualization scenarios, permissions set on other systems, and also permissions on network shares. In my testing it did solve the issue I encountered. The ability to add additional groups allows other users to work around the issue without having to modify permissions on their host, which I think is always preferable. Thanks for the feedback, I appreciate you taking the time to work on this!

@pSpitzner pSpitzner merged commit fcf6b72 into pSpitzner:main Dec 8, 2025
2 checks passed
semohr pushed a commit that referenced this pull request Dec 9, 2025
…ROUPS env var (#239)

- Add EXTRA_GROUPS support for beetle user permissions
- Update docker/entrypoints/entrypoint_fix_permissions.sh
- Add group name validation
- Warn user if named group exists with different gid
- Add explicit check for user having existing group membership.
- Added changelog entry
- Separated group_add into its own entrypoint script (called by fix_permissions one)
- Split group_add logic into two functions
- Removed old Testing parts from Dockerfile and entrypoint
- Improved chown performance on macos

closes #234
---------

Co-authored-by: djdubd <2773193+djdubd@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: pSpitzner <github@makeitso.one>
semohr pushed a commit that referenced this pull request Dec 9, 2025
…ROUPS env var (#239)

- Add EXTRA_GROUPS support for beetle user permissions
- Update docker/entrypoints/entrypoint_fix_permissions.sh
- Add group name validation
- Warn user if named group exists with different gid
- Add explicit check for user having existing group membership.
- Added changelog entry
- Separated group_add into its own entrypoint script (called by fix_permissions one)
- Split group_add logic into two functions
- Removed old Testing parts from Dockerfile and entrypoint
- Improved chown performance on macos

closes #234
---------

Co-authored-by: djdubd <2773193+djdubd@users.noreply.github.com>
Co-authored-by: pSpitzner <github@makeitso.one>
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.

Beets-Flask Permission Issue: Cannot Delete Files Owned by Root

4 participants