Skip to content

fix(docker): carry Compose group_add supplementary groups past s6 privilege drop (#75627) - #75632

Open
kyssta-exe wants to merge 1 commit into
NousResearch:mainfrom
kyssta-exe:auto-fix/issue-75627
Open

fix(docker): carry Compose group_add supplementary groups past s6 privilege drop (#75627)#75632
kyssta-exe wants to merge 1 commit into
NousResearch:mainfrom
kyssta-exe:auto-fix/issue-75627

Conversation

@kyssta-exe

Copy link
Copy Markdown
Contributor

Summary

When a Hermes container is started with Docker Compose group_add (or --group-add on the CLI), the supplementary group is granted to the container's PID 1 at the kernel level, but is silently dropped from the actual Hermes runtime process. The s6-setuidgid privilege drop calls initgroups() for the target user, which rebuilds the supplementary group list from /etc/group. Without an /etc/group entry matching the granted GID, the group is wiped between PID 1 and the dropped process — so bind-mounted directories that rely on a shared Unix group (e.g. a core.sharedRepository group Git checkout owned by host UID 1000:GID 1001) are unwritable by Hermes.

This is the same mechanism already handled for the Docker socket case (#16703) in docker/stage2-hook.sh; this PR generalizes it.

Fix

docker/stage2-hook.sh: after the existing docker.sock group block, read PID 1's supplementary group list from /proc/1/status and, for each granted GID:

  • skip gid 0 (root) and any GID hermes is already a member of (idempotent restarts, no interference with the docker.sock path which runs first),
  • resolve or create an /etc/group entry for the GID,
  • usermod -aG hermes into it.

Skipped silently when no supplementary groups are granted (the common case).

Verification

Tested in a real container (debian:bookworm-slim, --group-add 1001, hermes user UID 10000 like the Dockerfile):

=== BEFORE fix block ===
PID1 status Groups: 0 1001
hermes groups before: 10000
privilege-drop sim before (initgroups wipe): 10000     <- group 1001 wiped

=== RUNNING NEW FIX BLOCK ===
[stage2] Created group hostgroup1001 (GID 1001) for Compose group_add / --group-add
[stage2] Added hermes to group hostgroup1001 (GID 1001) from --group-add

=== AFTER fix block ===
hermes groups after: 10000 1001
privilege-drop sim after (initgroups): 10000 1001       <- group 1001 retained
RESULT: PASS

sh -n syntax check passes; the block is idempotent on re-run.

Closes #75627

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for generalizing the existing socket-group repair. The premise is confirmed on current main: docker/stage2-hook.sh:127-135 states that --group-add is lost through s6-setuidgid, but the current repair loop at docker/stage2-hook.sh:147-172 only runs for mounted Docker sockets. The proposed PID 1 group loop is consistent with that existing mechanism.

Problems

  • The PR changes only docker/stage2-hook.sh and adds no regression test. This behavior depends on the real s6 lifecycle; the repository's Docker harness builds and runs the image in tests/docker/conftest.py:52-70, while the main command performs the relevant privilege drop in docker/main-wrapper.sh:22.

Suggested changes

  • Add a Docker integration test that runs the image with --group-add 1001 and asserts the main runtime process retains GID 1001 after cont-init and s6-setuidgid.

This is an automated hermes-sweeper review.

Comment thread docker/stage2-hook.sh
# supplementary groups are granted (the common case). Avoids the
# well-known groups that must NOT be granted: the socket case above
# already handles docker.sock, and we deliberately skip gid 0 (root).
pid1_groups="$(sed -n 's/^Groups:[[:space:]]*//p' /proc/1/status 2>/dev/null || true)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add a real-image Docker regression test for this block: launch with --group-add 1001 and assert a command reached through main-wrapper.sh retains 1001 after s6-setuidgid. The existing tests/docker/conftest.py harness is designed for that lifecycle.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists backend/docker Docker container execution area/docker Docker image, Compose, packaging sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 31, 2026
@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 31, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

One PR addresses #75627. #75632 directly targets the reported cause by carrying PID 1's Docker-granted supplementary GIDs into /etc/group membership for the hermes user before s6-setuidgid rebuilds the group list.

Related pull requests

Suggested consolidation

Keep #75632 open with a salvage path: retain its focused PID 1 supplementary-group repair, but require the author to add the requested Docker integration test using --group-add 1001 and verify that the runtime command reached through main-wrapper.sh retains GID 1001 after cont-init and s6-setuidgid. There are no competing PRs to close as duplicates.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I75627(["issue #75627 (open)"])
    P75632["PR #75632 (open)"]
    P75632 -->|best fix| I75627
    class I75627 open
    class P75632 open
    class P75632 best
    class P75632 target
    click I75627 "https://github.com/NousResearch/hermes-agent/issues/75627"
    click P75632 "https://github.com/NousResearch/hermes-agent/pull/75632"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 1 pull request and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 3 kB of PR diffs, 8 kB of issue/PR text, 1 kB of discussion (2 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docker Docker image, Compose, packaging backend/docker Docker container execution P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Supplementary groups from Docker Compose group_add are dropped for the Hermes runtime user

4 participants