Skip to content

sandbox upload dereferences symlinks — uploaded as real directories, breaking git #1425

@rh-hemartin

Description

@rh-hemartin

Agent Diagnostic

Investigated by running the reproduction steps manually using openshell sandbox upload against a minimal git repository containing a symlink. Confirmed the symlink is absent in the sandbox and replaced by a regular directory. Tested on v0.0.36 and v0.0.42 — both exhibit the same behavior. Could not resolve — this requires a fix in the upload tar-building logic.

Description

openshell sandbox upload resolves symlinks in the source tree when building the tar archive. Symlinks arrive in the sandbox as regular directories (their targets, expanded inline). Git tracks them as symlink blobs, so git status in the sandbox immediately reports every symlink path as deleted:.

What should happen: Symlinks should be preserved as symlinks in the sandbox, matching the source tree exactly.

Reproduction Steps — v0.0.36

# 1. Download openshell v0.0.36 (Linux x86_64)
curl -L https://github.com/NVIDIA/OpenShell/releases/download/v0.0.36/openshell-x86_64-unknown-linux-musl.tar.gz \
  | tar -xz -C /tmp/openshell-036 --one-top-level
chmod +x /tmp/openshell-036/openshell

# 2. Create a minimal git repo with a symlink
mkdir /tmp/symlink-repro && cd /tmp/symlink-repro
git init -q
mkdir real-dir && echo "hello" > real-dir/file.txt
ln -s real-dir link-dir
git add . && git commit -qm "init"

# 3. Create a sandbox (requires a running gateway)
/tmp/openshell-036/openshell sandbox create --name symlink-test --keep --no-tty -- true

# 4. Upload the repo
/tmp/openshell-036/openshell sandbox upload symlink-test /tmp/symlink-repro /sandbox/repo

# 5. Check for symlinks — expect one, get none
/tmp/openshell-036/openshell sandbox exec --name symlink-test --no-tty -- /usr/bin/find /sandbox/repo -type l
# (no output)

# 6. Confirm link-dir is a real directory instead of a symlink
/tmp/openshell-036/openshell sandbox exec --name symlink-test --no-tty -- /usr/bin/ls -la /sandbox/repo/symlink-repro/

# 7. Clean up
/tmp/openshell-036/openshell sandbox delete symlink-test

Reproduction Steps — v0.0.42 (standalone gateway)

# 1. Download openshell v0.0.42 binaries (Linux x86_64)
mkdir /tmp/openshell-042
curl -L https://github.com/NVIDIA/OpenShell/releases/download/v0.0.42/openshell-x86_64-unknown-linux-musl.tar.gz \
  | tar -xz -C /tmp/openshell-042
curl -L https://github.com/NVIDIA/OpenShell/releases/download/v0.0.42/openshell-gateway-x86_64-unknown-linux-gnu.tar.gz \
  | tar -xz -C /tmp/openshell-042
curl -L https://github.com/NVIDIA/OpenShell/releases/download/v0.0.42/openshell-sandbox-x86_64-unknown-linux-gnu.tar.gz \
  | tar -xz -C /tmp/openshell-042
chmod +x /tmp/openshell-042/openshell /tmp/openshell-042/openshell-gateway /tmp/openshell-042/openshell-sandbox

# 2. Start the standalone gateway (Podman driver, no TLS for local testing)
OPENSHELL_SSH_HANDSHAKE_SECRET=test-secret \
  /tmp/openshell-042/openshell-gateway \
  --disable-tls \
  --disable-gateway-auth \
  --drivers podman \
  --db-url sqlite:///tmp/openshell-042-test.db \
  --port 8081 \
  --bind-address 0.0.0.0 \
  --docker-supervisor-bin /tmp/openshell-042/openshell-sandbox \
  &

# 3. Register and select the gateway
/tmp/openshell-042/openshell gateway add http://127.0.0.1:8081 --name gw-042
/tmp/openshell-042/openshell gateway select gw-042

# 4. Create the same minimal git repo (skip if already done above)
mkdir -p /tmp/symlink-repro && cd /tmp/symlink-repro
git init -q
mkdir -p real-dir && echo "hello" > real-dir/file.txt
ln -sf real-dir link-dir
git add . && git commit -qm "init" 2>/dev/null || true

# 5. Create a sandbox
/tmp/openshell-042/openshell sandbox create --name symlink-test --keep --no-tty -- true

# 6. Upload the repo
/tmp/openshell-042/openshell sandbox upload symlink-test /tmp/symlink-repro /sandbox/repo

# 7. Check for symlinks — expect one, get none
/tmp/openshell-042/openshell sandbox exec --name symlink-test --no-tty -- /usr/bin/find /sandbox/repo -type l
# (no output)

# 8. Confirm link-dir is a real directory
/tmp/openshell-042/openshell sandbox exec --name symlink-test --no-tty -- /usr/bin/ls -la /sandbox/repo/symlink-repro/

# 9. Clean up
/tmp/openshell-042/openshell sandbox delete symlink-test
kill %1

Expected output (step 5 / step 7)

/sandbox/repo/symlink-repro/link-dir

Actual output (step 5 / step 7)

(empty)

ls -la shows link-dir as a regular directory in both versions:

drwxr-xr-x. 1 sandbox sandbox 16 ... link-dir
drwxr-xr-x. 1 sandbox sandbox 16 ... real-dir

Environment

  • openshell: 0.0.36 and 0.0.42 (both affected)
  • OS: Linux x86_64
  • Driver: Podman (rootless)

Impact

Any workflow uploading a git repo with symlinks will see those paths reported as deleted: by git status inside the sandbox, even though the working tree is otherwise intact. This causes spurious git noise and can lead agents to attempt restoring files that were never deleted.

Agent-First Checklist

  • I pointed my agent at the repo and had it investigate this issue
  • I loaded relevant skills (e.g., debug-openshell-cluster, debug-inference, openshell-cli)
  • My agent could not resolve this — the diagnostic above explains why

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions