Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/agentex/lib/cli/templates/PRIVATE_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,38 @@ The name must be exactly `scale-pypi`. uv applies `UV_INDEX_SCALE_PYPI_USERNAME`
silently stop applying. Setting `UV_INDEX_URL` instead does not authenticate a *named* index at
all, and the resolve fails with a 401.

## The secret is scoped to the dependency step only

`Dockerfile-uv.j2` installs in two steps, and only the first one mounts the broker secret:

| Step | What it does | Secret |
| --- | --- | --- |
| `uv sync --no-install-project` | resolves and installs dependencies, private ones included | mounted |
| `uv sync` (after `COPY project`) | builds and installs the agent's own project | **not mounted** |

The second step runs the agent's own PEP 517 build backend, and that is project-controlled
code — an in-tree `backend-path` module, or whatever `[build-system] requires` names. With the
secret mounted there it can read `/run/secrets/codeartifact-pip-conf` and the decoded
`UV_INDEX_SCALE_PYPI_PASSWORD`, and the build has network, so the CodeArtifact token can go
anywhere. That is the same threat this file already describes below — a contributed change to a
*project* file, far less conspicuous in review than a `curl` in the Dockerfile — and it needs
only files the templates already copy: `pyproject.toml` and something under `project/`.

Reproduced against the previous layout, then re-run against this one:

| | secret on both steps | secret on step 1 only |
| --- | --- | --- |
| build succeeds | yes | yes |
| package from the private index installs | yes | **yes** |
| build backend reads the secret file | **yes** | `<absent>` |
| build backend reads the decoded token | **yes** | `<unset>` |

Nothing is lost by dropping it: dependencies are already installed by the first step, so the
second has nothing left to fetch from the mirror.

`Dockerfile.j2` (the `requirements.txt` variant) never had this problem — it installs and only
then copies the project, so no project-controlled code runs while the secret is mounted.

## Three things that are easy to get wrong

**The token arrives percent-encoded.** The buildspec URL-encodes it to embed it in the pip config's
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/default-claude-code/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/default-codex/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/default-langgraph/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/default-pydantic-ai/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/default/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/sync-claude-code/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/sync-codex/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/sync-langgraph/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
18 changes: 10 additions & 8 deletions src/agentex/lib/cli/templates/sync-openai-agents/Dockerfile-uv.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ RUN --mount=type=cache,target=/root/.cache/uv \
# Copy the project code
COPY {{ project_path_from_build_root }}/project ./project

# Install the project
# Install the project.
#
# No broker secret on this step, deliberately. Unlike the step above, this one runs the
# agent's OWN build backend — and a PEP 517 backend is project-controlled code (an
# in-tree `backend-path` module, or whatever `[build-system] requires` names). With the
# secret mounted here it could read /run/secrets/codeartifact-pip-conf and the decoded
# UV_INDEX_SCALE_PYPI_PASSWORD and send the CodeArtifact token anywhere; the build has
# network. Reproduced before this change. Dependencies — including the private ones —
# are already installed by the step above, so nothing is lost by dropping it here.
# See PRIVATE_INDEX.md.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=secret,id=codeartifact-pip-conf,required=false \
if [ -s /run/secrets/codeartifact-pip-conf ]; then \
export UV_INDEX="scale-pypi=$(sed -n 's#.*index-url = https://aws:[^@]*@\(.*\)#https://\1#p' /run/secrets/codeartifact-pip-conf | head -1)"; \
export UV_INDEX_SCALE_PYPI_USERNAME=aws; \
export UV_INDEX_SCALE_PYPI_PASSWORD="$(sed -n 's#.*index-url = https://aws:\([^@]*\)@.*#\1#p' /run/secrets/codeartifact-pip-conf \
| python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read().strip()))')"; \
fi; \
uv sync --no-dev

ENV PATH="/app/{{ project_path_from_build_root }}/.venv/bin:$PATH"
Expand Down
Loading
Loading