uv icon indicating copy to clipboard operation
uv copied to clipboard

installing private repo in Dockerfile fails with uv, works with poetry

Open captnswing opened this issue 1 year ago β€’ 13 comments

Hello! and congratulations on the bombastic release of uv 0.3.0! I've been using poetry for a while now and I'm excited to try out uv as a replacement.

My project has a dependency to a private GHE repo. In the pyproject.toml I use with poetry, I have the following

[tool.poetry.dependencies]
...
<mypackage> = { git = "git+ssh://[email protected]/<org>/<mypackage>.git", rev = "release-XYZ" }
...

building the Docker container on my host with

eval $(ssh-agent) && ssh-add ~/.ssh/<ghe_ssh_key> 
DOCKER_BUILDKIT=1 docker build --ssh default .

the following Dockerfile always used to work with poetry, installing the package from the private GHE repo in the container

...
COPY poetry.lock pyproject.toml ./

RUN --mount=type=ssh \
    # suppress hostkey checking
    mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts && \
    # install project requirements
    poetry install --only main
...

Switching to uv, I made the necessary adjustments to pyproject.toml (and uv sync works on the host)

...
dependencies = [
    ...
    <mypackage>,
    ...
]

[tool.uv.sources]
<mypackage> = { git = "git+ssh://[email protected]/<org>/<mypackage>.git", rev = "release-XYZ" }
...

the relevant section of my Dockerfile now looks like this

...
RUN curl -LsSf https://astral.sh/uv/0.3.0/install.sh | sh

COPY uv.lock pyproject.toml ./

RUN --mount=type=ssh \
    # suppress hostkey checking
    mkdir -p -m 0600 ~/.ssh && ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts && \
    # install project requirements
    $HOME/.cargo/bin/uv sync --no-dev --frozen
...    

running

eval $(ssh-agent) && ssh-add ~/.ssh/<ghe_ssh_key> 
DOCKER_BUILDKIT=1 docker build --ssh default .

again fails with

...
3.217 [email protected]: Permission denied (publickey).
3.217 fatal: Could not read from remote repository.
3.217 
3.217 Please make sure you have the correct access rights
3.217 and the repository exists.
...

Feels like uv ignores the ssh key passed to the container with --mount=type=ssh?

What am I missing? How can I install the private repo with uv in the Dockerfile?

captnswing avatar Aug 21 '24 07:08 captnswing

Thanks. What you're doing looks right -- I'll test it out today and report back.

charliermarsh avatar Aug 21 '24 13:08 charliermarsh

Confirming that I've reproduced.

charliermarsh avatar Aug 21 '24 14:08 charliermarsh

Ahhh it's because we're stripping the username in the lockfile (git@ in [email protected]).

charliermarsh avatar Aug 21 '24 14:08 charliermarsh

I'll fix this for today's release, sorry.

charliermarsh avatar Aug 21 '24 14:08 charliermarsh

just... wow 🀩 and thank you, Charlie and team astral.sh πŸš€ πŸ™‡πŸΌ

captnswing avatar Aug 21 '24 16:08 captnswing

So I tried the fresh new release of uv 0.3.1 (πŸ™ŒπŸΌ) and it seems that it doesn't write git@ user to the lock file.

My session:

❯ uv --version
uv 0.3.1 (be17d132a 2024-08-21)
❯ rm uv.lock                     
❯ uv lock
 Updated git+ssh://[email protected]/<my_org>/<my_package>.git (6f3be93)
Resolved 121 packages in 3.80s
❯ grep -B 1 'git@' pyproject.toml 
[tool.uv.sources]
<my_package> = { git = "git+ssh://[email protected]/<my_org>/<my_package>.git", rev = "release-0.3.24" }
❯ grep -B 1 'git@' uv.lock       
 
❯ eval $(ssh-agent) && ssh-add ~/.ssh/<my_ghe_key> 
Agent pid 17176
Identity added: <my_ghe_key>

❯ DOCKER_BUILDKIT=1 docker build --ssh default .
...
3.611 --- stderr
3.611 [email protected]: Permission denied (publickey).
3.611 fatal: Could not read from remote repository.
3.611 
3.611 Please make sure you have the correct access rights
3.611 and the repository exists.
3.611 
...

uv sync works on the host (a Mac), with the lockfile written (without git@ user), but fails in the docker build (using python:3.11-bookworm base image).

I can confirm that manually adding git@ to the repo url in uv.lock makes the docker build work.

But it seems that uv 0.3.1 writes the lock file without the git@ user.

captnswing avatar Aug 22 '24 07:08 captnswing

Is there any chance that your Docker build is still getting v0.3.0? Perhaps you’re using the CURL installer and the layer is still cached?

charliermarsh avatar Aug 22 '24 11:08 charliermarsh

The relevant section of the Dockerfile looks like this

RUN curl -LsSf https://astral.sh/uv/0.3.1/install.sh | sh
COPY uv.lock pyproject.toml README.md ./
RUN --mount=type=ssh \
    # suppress hostkey checking
    mkdir -p -m 0600 ~/.ssh && ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts && \
    # install project requirements according to the lock file, without dev dependencies
    $HOME/.cargo/bin/uv sync --no-dev

I even added ENV foo=bar above to force rebuild of these layers, same result.

Isn't the tell-tale sign that the uv.lock file generated by uv 0.3.1 on the host (and that's copied into the container) does not contain git@ anywhere?

❯ rm uv.lock && uv --version && uv lock
uv 0.3.1 (be17d132a 2024-08-21)
 Updated git+ssh://[email protected]/<myorg>/<mypackage>.git (6f3be93)
Resolved 121 packages in 6.02s

❯ grep 'git@' uv.lock       

after I manually add git@ to the url in uv.lock, the docker build works.

uv sync works on the host, whether or not git@ is present on the github url in uv.lock 🀷🏼

captnswing avatar Aug 22 '24 13:08 captnswing

same with uv 0.3.2

captnswing avatar Aug 23 '24 07:08 captnswing

working around it now by adding the RUN sed -i ... step to the Dockerfile

FROM python:3.11-bookworm
WORKDIR /opt

# Install uv
COPY --from=ghcr.io/astral-sh/uv:0.3.3 /uv /bin/uv

# Copy files needed for uv sync
COPY uv.lock pyproject.toml ./

# https://github.com/astral-sh/uv/issues/6305
RUN sed -i 's|git+ssh://github.com|git+ssh://[email protected]|g' uv.lock

# Install the dependencies for the project into /opt/.venv
# Access to key agent needed to install package from private git repo
RUN --mount=type=ssh \
    # suppress hostkey checking
    mkdir -p -m 0600 ~/.ssh && ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts && \
    # install project requirements according to the lock file, without dev dependencies
    uv sync --no-dev --frozen --no-install-project

...

captnswing avatar Aug 24 '24 10:08 captnswing

@captnswing -- Just confirming -- still a problem? Can look into it today.

charliermarsh avatar Aug 27 '24 13:08 charliermarsh

yes, actually this still isn't working (on my machine...)

I've been banging my head against what could be the problem in my environment that could be the cause, so I tried to create reproducable scripts and run them from a clean docker slate docker system prune -a, (and using uv 0.3.3)

Test plan

  1. generate uv.lock on the host (the case originally reported here)
  2. generate uv.lock in the container (not really what I need, but just to see what happens)
  3. compare the host-generated and the container-generated uv.lock files to see if / how they differ

Results

case 1.) πŸ›‘ docker build -ssh ... fails with [email protected]: Permission denied (publickey) as reported here (even after docker system prune)

case 2.) βœ… docker build -ssh ... works 🀷🏼

case 3.) ❓❗the container- and host-generated uv.lock files are identical 😳

Appendix: scripts used

host_generated.sh
#!/bin/sh
eval $(ssh-agent)
ssh-add ~/.ssh/id_ghe
rm -f uv.lock && uv lock
cat <<EOL >Dockerfile.host_generated
    FROM python:3.11-bookworm
    COPY --from=ghcr.io/astral-sh/uv:0.3.3 /uv /bin/uv
    WORKDIR /app
    COPY pyproject.toml uv.lock .
    RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
    RUN --mount=type=ssh uv sync --frozen --no-dev --no-install-project
EOL
DOCKER_BUILDKIT=1 docker build --no-cache --ssh default -t host_generated -f Dockerfile.host_generated .
container_generated.sh
#!/bin/sh
eval $(ssh-agent)
ssh-add ~/.ssh/id_ghe
cat <<EOL >Dockerfile.container_generated
    FROM python:3.11-bookworm
    COPY --from=ghcr.io/astral-sh/uv:0.3.3 /uv /bin/uv
    WORKDIR /app
    COPY pyproject.toml .
    RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
    RUN --mount=type=ssh uv lock
    RUN --mount=type=ssh uv sync --no-dev --no-install-project
EOL
DOCKER_BUILDKIT=1 docker build --no-cache --ssh default -t container_generated -f Dockerfile.container_generated .
diff_lockfiles.sh.sh
#!/bin/sh
# copy the tarfile from the container to a tmp_dir on the host
tmp_dir=$(mktemp -d)
docker cp $(docker create container_generated):/app/uv.lock - > $tmp_dir/uv_container.lock.tar
tar -xf $tmp_dir/uv_container.lock.tar -C $tmp_dir
# move container lockfile from tmp_dir to current directory, not overwriting the host lockfile
mv $tmp_dir/uv.lock uv_container.lock
# cleanup
rm -rf $tmp_dir
# diff the lockfiles
if diff -q uv.lock uv_container.lock; then
    echo "The files are identical."
else
    diff uv.lock uv_container.lock
fi

captnswing avatar Aug 27 '24 20:08 captnswing

I had a simlar issue where lockfile generated by uv v3 was giving me errors when running uv sync inside the container, but upgrading uv to v4 fixed the issue for me.

nikhilweee avatar Sep 10 '24 00:09 nikhilweee

great! I'm not crazy 🀣

This works now. using my scripts, I could triangulate it to uv 0.4.10

so uv 0.4.10 is the last version that had the reported behaviour, and it works since uv 0.4.11

thanks for making uv @charliermarsh !

captnswing avatar Sep 21 '24 12:09 captnswing