Skip to content

feat(drivers): inject local sandbox identity#2335

Draft
matthewgrossman wants to merge 3 commits into
mainfrom
mgrossman/remove-sandbox-user
Draft

feat(drivers): inject local sandbox identity#2335
matthewgrossman wants to merge 3 commits into
mainfrom
mgrossman/remove-sandbox-user

Conversation

@matthewgrossman

Copy link
Copy Markdown
Contributor

🏗️ build-from-issue-agent

Summary

Make the Docker and Podman compute drivers choose and inject a validated numeric agent identity at runtime, so OpenShell-managed sandboxes no longer require a baked-in sandbox user or group. The supervisor now presents the same numeric identity and /sandbox home consistently for primary and SSH-launched agent processes.

Related Issue

Closes #2331

Changes

  • Docker and Podman default to UID/GID 10001:10001, support operator overrides, validate both values against the policy identity range, and override image/user-supplied identity environment variables.
  • The process supervisor sets HOME, USER, and LOGNAME consistently when dropping to a numeric identity.
  • Added a shared userless image fixture and Docker/Podman E2E coverage proving the agent identity and workspace remain usable without passwd/group entries.
  • Documented the new driver configuration and clarified that image USER is not authoritative for an OpenShell-managed agent.

Deviations from Plan

Local Docker validation completed. Podman is not installed on this development host, so the new Podman E2E target was compiled locally and is left to the repository's rootless Podman CI lane for runtime validation.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated

Tests added:

  • Unit: Docker and Podman defaulting, partial overrides, invalid ranges, and protected environment precedence; supervisor numeric identity environment behavior.
  • Integration: Docker and Podman feature variants of custom_image compile.
  • E2E: docker_sandbox_from_userless_dockerfile passes locally; podman_sandbox_from_userless_image is covered by rootless Podman CI.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated

Documentation updated:

  • architecture/compute-runtimes.md and architecture/sandbox.md: runtime identity ownership and flow.
  • Driver READMEs, gateway configuration reference/sample, and BYOC example: operator configuration and userless image expectations.

Make Docker and Podman select a validated numeric agent identity and inject it into the supervisor, allowing userless images to run without a baked-in sandbox account.\n\nCloses #2331

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@github-actions

Copy link
Copy Markdown

Thank you for your interest in contributing to OpenShell, @matthewgrossman.

This project uses a vouch system for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer.

To get vouched:

  1. Open a Vouch Request discussion.
  2. Describe what you want to change and why.
  3. Write in your own words — do not have an AI generate the request.
  4. A maintainer will comment /vouch if approved.
  5. Once vouched, open a new PR (preferred) or reopen this one after a few minutes.

See CONTRIBUTING.md for details.

@github-actions github-actions Bot closed this Jul 16, 2026
@matthewgrossman

Copy link
Copy Markdown
Contributor Author

🏗️ build-from-issue-agent

E2E Test Attestation

The local Docker E2E test passed against the committed implementation. Podman is not installed on this development host; the PR adds the equivalent test to the repository's rootless Podman E2E lane.

Field Value
Commit 98ef34f6
Command OPENSHELL_E2E_DOCKER_TEST=custom_image mise run e2e:docker
Gateway mode Docker
Result ✅ All passed

Test Summary

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Tests Executed

  • e2e/rust/tests/custom_image.rs::docker_sandbox_from_userless_dockerfile — PASSED

The fixture asserts that the image contains neither a named sandbox account nor UID/GID 10001, then verifies that the managed agent runs as 10001:10001, receives HOME=/sandbox, and can write to that directory.

@github-actions

Copy link
Copy Markdown

Thank you for your interest in contributing to OpenShell, @matthewgrossman.

This project uses a vouch system for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer.

To get vouched:

  1. Open a Vouch Request discussion.
  2. Describe what you want to change and why.
  3. Write in your own words — do not have an AI generate the request.
  4. A maintainer will comment /vouch if approved.
  5. Once vouched, open a new PR (preferred) or reopen this one after a few minutes.

See CONTRIBUTING.md for details.

Comment on lines +170 to +171
sandbox_uid: None,
sandbox_gid: None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

QUestion: Why is the default not DEFAULT_SANDBOX_UID?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the idea was to keep all of the resolution within resolve_sandbox_entity, versus defaulting in multiple locations. But I do think that's a bit confusing, I think it's worth updating here IMO

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated this so the Docker and Podman configs now use DEFAULT_SANDBOX_UID as a concrete UID default. We keep sandbox_gid optional so that, when it is omitted, it follows the selected UID (for example, a UID-only override of 12345 resolves to 12345:12345). That matches the effective UID/GID fallback behavior in the Kubernetes and VM drivers.

Comment on lines +91 to +98
/// Numeric UID for the agent process. Defaults to 10001.
#[arg(long, env = "OPENSHELL_PODMAN_SANDBOX_UID")]
sandbox_uid: Option<u32>,

/// Numeric GID for the agent process. Defaults to the resolved UID.
#[arg(long, env = "OPENSHELL_PODMAN_SANDBOX_GID")]
sandbox_gid: Option<u32>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Out of scope for this change, but is annonymous struct embedding possible in rust so that one could group common driver options like these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

so it looks like to be a non-native feature, but serde has their flatten https://serde.rs/attr-flatten.html

  • Clap: #[command(flatten)]
  • Serde: #[serde(flatten)]

For example:

struct SandboxIdentityArgs {
    #[arg(long)]
    sandbox_uid: Option<u32>,
    #[arg(long)]
    sandbox_gid: Option<u32>,
}

struct Args {
    #[command(flatten)]
    sandbox_identity: SandboxIdentityArgs,
}

Looks like we do use it in some places:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

(thanks for giving an excuse to do an learning-dive on how derive macros work)

so yes this is something we could do, but I wonder if we wait until some amount of these common attributes stabilized in beta+? I mean they're all new to me, so maybe they are stable and I just don't know

Comment thread e2e/fixtures/userless/Dockerfile Outdated
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

FROM public.ecr.aws/docker/library/python:3.13-slim

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Question: Why not something even smaller? Do we need python?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

nope we don't, swapped this to debian bookwork slim

Comment on lines +9 to +10
//! - A running Docker- or Podman-backed OpenShell gateway
//! - Docker or Podman runtime running (for image build)

@elezar elezar Jul 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do these strictly need Docker or Podman drivers? (not for image build).

@matthewgrossman
matthewgrossman marked this pull request as draft July 17, 2026 17:22
@copy-pr-bot

copy-pr-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@github-actions

Copy link
Copy Markdown

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.

feat: complete Docker and Podman runtime identity injection

2 participants