mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-11 03:13:16 +00:00
feat(paseo): install SDKMAN on start, and rename the wrapper entrypoint
SDKMAN goes into ~/.sdkman whenever that directory is missing, the same way the agent CLIs arrive: as paseo, through gosu, onto the volume, where `sdk install` can write and the candidates persist. No variable gates it. The chown of /home/paseo moves out of the AGENT_CLIS guard, since SDKMAN now needs it even when no agent is named, and the agent loop reads AGENT_CLIS into a local first so `set -u` does not trip on it being unset. SDKMAN_DIR is set in the image, and the current/bin of java, scala, gradle, maven and sbt joins PATH: `sdk` itself is a shell function from the rc hook and so exists in terminals only, while the daemon and an agent's non-interactive commands read no rc file and need the binaries on PATH. paseo-sudo-entrypoint was named for the one thing it used to do. It is /usr/local/bin/entrypoint now, matching the source file.
This commit is contained in:
1 parent
07991dabaf
commit
f02de334e5
3 files changed
+62
-19
No files matched your search
+12
-7
@@ -44,12 +44,17 @@ RUN install -d -m 0755 /etc/apt/keyrings \
|
||||
&& rm -f /tmp/glab.deb \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# --- agent cli path --------------------------------------------------------
|
||||
# Puts the $HOME directories the agent installers write to on PATH.
|
||||
ENV PATH=/home/paseo/.local/bin:/home/paseo/.opencode/bin:$PATH
|
||||
# --- agent cli and sdkman path ---------------------------------------------
|
||||
# Puts the $HOME directories the agent installers and SDKMAN write to on PATH.
|
||||
ENV SDKMAN_DIR=/home/paseo/.sdkman
|
||||
ENV PATH=/home/paseo/.local/bin:/home/paseo/.opencode/bin:\
|
||||
$SDKMAN_DIR/candidates/java/current/bin:\
|
||||
$SDKMAN_DIR/candidates/scala/current/bin:\
|
||||
$SDKMAN_DIR/candidates/gradle/current/bin:\
|
||||
$SDKMAN_DIR/candidates/maven/current/bin:\
|
||||
$SDKMAN_DIR/candidates/sbt/current/bin:$PATH
|
||||
|
||||
# --- entrypoint ------------------------------------------------------------
|
||||
# Wraps the image's entrypoint to set the paseo user's password while still
|
||||
# root -- see entrypoint.sh.
|
||||
COPY --chmod=0755 entrypoint.sh /usr/local/bin/paseo-sudo-entrypoint
|
||||
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/paseo-sudo-entrypoint"]
|
||||
# Wraps the image's entrypoint with the root-stage setup -- see entrypoint.sh.
|
||||
COPY --chmod=0755 entrypoint.sh /usr/local/bin/entrypoint
|
||||
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint"]
|
||||
+38
-8
@@ -4,8 +4,8 @@
|
||||
agents. Built from a local `Dockerfile` that adds `gh`, `glab`, Go, Python,
|
||||
a C toolchain, and shell tooling to the
|
||||
[official image](https://paseo.sh/docs/docker), which ships none of it. The
|
||||
agent CLIs are not baked in — install them into `$HOME` yourself, see
|
||||
[Agents](#agents).
|
||||
agent CLIs and [SDKMAN](#sdkman) are not baked in; `entrypoint.sh` installs
|
||||
them into `$HOME` on start, see [Agents](#agents).
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -122,11 +122,37 @@ themselves in place afterwards.
|
||||
Pi and Oh My Pi are separate projects sharing an ancestor; their commands do
|
||||
not collide.
|
||||
|
||||
## SDKMAN
|
||||
|
||||
`entrypoint.sh` installs [SDKMAN](https://sdkman.io) on start too, into
|
||||
`~/.sdkman`, whenever that directory is missing. No variable gates it — the
|
||||
JVM toolchain is small next to an agent CLI and the image ships no Java at all.
|
||||
|
||||
Install what you need from a terminal:
|
||||
|
||||
```
|
||||
sdk install java
|
||||
sdk install gradle
|
||||
```
|
||||
|
||||
`sdk` is a shell function, defined by the hook the installer appends to
|
||||
`.bashrc` and `.zshrc`, so it exists in terminals only. The `current/bin`
|
||||
directory of five candidates — `java`, `scala`, `gradle`, `maven`, `sbt` — is
|
||||
on the image's `PATH` regardless, so the binaries themselves resolve for the
|
||||
daemon and for commands an agent runs non-interactively, where no rc file is
|
||||
read. Install a candidate outside that five and you get the `sdk` function in a
|
||||
terminal but not the binary elsewhere; add its `current/bin` to the `PATH` line
|
||||
in the `Dockerfile` if you want it there.
|
||||
|
||||
`SDKMAN_DIR` is set in the image, to the same `~/.sdkman` the installer would
|
||||
have picked on its own. It is what puts the candidate paths above and the
|
||||
install location in one place.
|
||||
|
||||
## Storage
|
||||
|
||||
| Volume | Mount | Holds |
|
||||
| --- | --- | --- |
|
||||
| `paseo-home` | `/home/paseo` | Daemon state, agent configs, credentials (`.claude`, `.codex`, `.config/*`) |
|
||||
| `paseo-home` | `/home/paseo` | Daemon state, agent CLIs and their configs and credentials (`.claude`, `.codex`, `.config/*`), SDKMAN and its candidates |
|
||||
| `paseo-workspace` | `/workspace` | Code the agents work on |
|
||||
|
||||
The agent CLIs, `gh` and `glab` all keep their config under `/home/paseo`, so
|
||||
@@ -170,18 +196,22 @@ all here:
|
||||
it and puts `paseo` in the group.
|
||||
- The image stays root: the entrypoint chowns the volumes, then drops to the
|
||||
`paseo` user (uid 1000) with `gosu`.
|
||||
- `entrypoint.sh` is installed as `/usr/local/bin/entrypoint`, next to the
|
||||
base image's `paseo-docker-entrypoint`, which it wraps. It was
|
||||
`paseo-sudo-entrypoint` when setting the `sudo` password was all it did.
|
||||
- `entrypoint.sh` runs before the base entrypoint, not after: that one ends in
|
||||
`exec gosu paseo` and never returns, and by then is no longer root. Both of
|
||||
its jobs need root — `chpasswd`, and `gosu paseo` for the agent installs.
|
||||
`exec gosu paseo` and never returns, and by then is no longer root. Every
|
||||
job it has needs root — `chpasswd`, the `chown`, and `gosu paseo` for the
|
||||
SDKMAN and agent installs.
|
||||
- It sets the `paseo` password on every start rather than at build, so the
|
||||
password never lands in an image layer, and because `/etc/shadow` is in the
|
||||
image rather than on a volume and reverts on each recreate. The password is
|
||||
piped, not passed as an argument, since arguments are visible in `ps`;
|
||||
`chpasswd` splits on the first colon, so a colon in the password is fine. An
|
||||
empty `PASEO_PASSWORD` leaves the account locked and `sudo` unusable.
|
||||
- It also `chown`s `/home/paseo` before installing anything. A freshly created
|
||||
volume can arrive owned by root, and the base entrypoint's own `chown` has
|
||||
not run yet at that point.
|
||||
- It also `chown`s `/home/paseo` before installing anything, agent CLI or
|
||||
SDKMAN. A freshly created volume can arrive owned by root, and the base
|
||||
entrypoint's own `chown` has not run yet at that point.
|
||||
- `sudo` resets `PATH` to its `secure_path`, which excludes
|
||||
`/usr/local/go/bin`. Use `sudo env PATH="$PATH" go ...` or the full path.
|
||||
- The agent `PATH` entries belong in the image, not in a shell rc: the daemon
|
||||
|
||||
+12
-4
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Runs as root ahead of the image's own entrypoint: sets the paseo user's
|
||||
# login password, then installs any agent CLI named in AGENT_CLIS that is not
|
||||
# already on PATH. See README.md.
|
||||
# login password, installs SDKMAN, then installs any agent CLI named in
|
||||
# AGENT_CLIS that is not already on PATH. See README.md.
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -u)" == "0" && -n "${PASEO_PASSWORD:-}" ]]; then
|
||||
@@ -19,10 +19,18 @@ agent_installer() {
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ "$(id -u)" == "0" && -n "${AGENT_CLIS:-}" ]]; then
|
||||
if [[ "$(id -u)" == "0" ]]; then
|
||||
chown paseo:paseo /home/paseo
|
||||
|
||||
for agent in ${AGENT_CLIS//,/ }; do
|
||||
if [[ ! -d "${SDKMAN_DIR:-/home/paseo/.sdkman}" ]]; then
|
||||
echo "entrypoint: installing sdkman"
|
||||
gosu paseo bash -c 'curl -fsSL https://get.sdkman.io | bash' \
|
||||
|| echo "entrypoint: sdkman failed to install, continuing" >&2
|
||||
fi
|
||||
|
||||
agents="${AGENT_CLIS:-}"
|
||||
|
||||
for agent in ${agents//,/ }; do
|
||||
installer="$(agent_installer "$agent")"
|
||||
|
||||
if [[ -z "$installer" ]]; then
|
||||
|
||||
Reference in new issue
Block a user