From 0aa3890fb85030d5dcb6d4b5177cba57d13def4d Mon Sep 17 00:00:00 2001 From: openhands Date: Tue, 24 Mar 2026 20:30:44 +0000 Subject: [PATCH] fix: Start cron daemon in agent container entrypoint (#618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The entrypoint installed a crontab but never started a cron daemon, leaving the container idle. Fix by running as root in the entrypoint (cron requires it), installing the crontab for the agent user via `crontab -u agent`, and starting cron in the foreground with `cron -f`. Remove `USER agent` from the Dockerfile and `user: "1000:1000"` from the compose template accordingly — cron jobs still execute as UID 1000. Co-Authored-By: Claude Opus 4.6 (1M context) --- bin/disinto | 1 - docker/agents/Dockerfile | 3 ++- docker/agents/entrypoint.sh | 28 ++++++++++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bin/disinto b/bin/disinto index b8d5964..bbe6d43 100755 --- a/bin/disinto +++ b/bin/disinto @@ -192,7 +192,6 @@ services: agents: build: ./docker/agents restart: unless-stopped - user: "1000:1000" volumes: - agent-data:/home/agent/data - project-repos:/home/agent/repos diff --git a/docker/agents/Dockerfile b/docker/agents/Dockerfile index d3b9ba2..2dc8a22 100644 --- a/docker/agents/Dockerfile +++ b/docker/agents/Dockerfile @@ -14,7 +14,8 @@ RUN useradd -m -u 1000 -s /bin/bash agent COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh -USER agent +# Entrypoint runs as root to start the cron daemon; +# cron jobs execute as the agent user (crontab -u agent). WORKDIR /home/agent ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/agents/entrypoint.sh b/docker/agents/entrypoint.sh index 00d5708..ce36e89 100644 --- a/docker/agents/entrypoint.sh +++ b/docker/agents/entrypoint.sh @@ -1,20 +1,22 @@ #!/usr/bin/env bash set -euo pipefail -# entrypoint.sh — Start agent container with cron and stay alive +# entrypoint.sh — Start agent container with cron in foreground # -# Installs crontab entries from project TOMLs found in the factory -# mount, then runs cron in the background and tails the log. +# Runs as root inside the container. Installs crontab entries for the +# agent user from project TOMLs, then starts cron in the foreground. +# All cron jobs execute as the agent user (UID 1000). -DISINTO_DIR="${HOME}/disinto" -LOGFILE="${HOME}/data/agent-entrypoint.log" -mkdir -p "${HOME}/data" +DISINTO_DIR="/home/agent/disinto" +LOGFILE="/home/agent/data/agent-entrypoint.log" +mkdir -p /home/agent/data +chown agent:agent /home/agent/data log() { printf '[%s] %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" | tee -a "$LOGFILE" } -# Build crontab from project TOMLs +# Build crontab from project TOMLs and install for the agent user. install_project_crons() { local cron_lines="" for toml in "${DISINTO_DIR}"/projects/*.toml; do @@ -34,8 +36,8 @@ with open(sys.argv[1], 'rb') as f: done if [ -n "$cron_lines" ]; then - printf '%s\n' "$cron_lines" | crontab - - log "Installed crontab for projects" + printf '%s\n' "$cron_lines" | crontab -u agent - + log "Installed crontab for agent user" else log "No project TOMLs found — crontab empty" fi @@ -44,8 +46,6 @@ with open(sys.argv[1], 'rb') as f: log "Agent container starting" install_project_crons -# Keep container alive — cron runs in foreground via tail on log -# (cron daemon needs root; since we run as agent, we use a polling approach -# or the host cron can be used via docker compose exec) -log "Agent container ready — waiting for work" -exec tail -f /dev/null +# Run cron in the foreground. Cron jobs execute as the agent user. +log "Starting cron daemon" +exec cron -f