diff --git a/cron/Dockerfile b/cron/Dockerfile index b9ad9ef..7c32432 100644 --- a/cron/Dockerfile +++ b/cron/Dockerfile @@ -11,10 +11,13 @@ RUN apk add --no-cache \ WORKDIR /app -# Install script dependencies at build time (into /opt so the ro volume mount doesn't shadow them) -COPY scripts/package*.json /opt/scripts-deps/ -RUN cd /opt/scripts-deps && npm install --omit=dev -ENV NODE_PATH=/opt/scripts-deps/node_modules +# Install script dependencies at /app/node_modules. The /app/scripts dir is +# a read-only host mount at runtime, so deps can't live inside it. Node ESM +# walks up from the importing file looking for node_modules — /app is the +# parent of /app/scripts, and /app itself is NOT mounted, so this works. +# (NODE_PATH is intentionally NOT used: ESM resolution ignores it.) +COPY scripts/package*.json ./ +RUN npm install --omit=dev COPY cron/crontab /etc/crontabs/root COPY cron/entrypoint.sh /entrypoint.sh diff --git a/cron/entrypoint.sh b/cron/entrypoint.sh index 58bf4a9..9c329e1 100644 --- a/cron/entrypoint.sh +++ b/cron/entrypoint.sh @@ -6,14 +6,34 @@ git config --global --add safe.directory /app git config --global user.email "wiki-bot@ghostguild.org" git config --global user.name "Wiki Bot" -# Add git remote host to known_hosts so SSH doesn't prompt -mkdir -p /root/.ssh_tmp -cp /root/.ssh/* /root/.ssh_tmp/ 2>/dev/null || true -ssh-keyscan -t ed25519,rsa git.ghostguild.org >> /root/.ssh_tmp/known_hosts 2>/dev/null -export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/root/.ssh_tmp/known_hosts -i /root/.ssh/id_ed25519" +# The repo's origin is HTTPS (so DokPloy can fetch), but the cron pushes via +# SSH using the mounted deploy key. Rewrite the URL only for push operations. +git config --global url."git@git.ghostguild.org:".pushInsteadOf "https://git.ghostguild.org/" -# Dump environment for cron jobs (crond doesn't inherit container env) -env | grep -v '^_=' | sed 's/^\(.*\)$/export \1/' > /etc/environment.sh +# /root/.ssh is mounted read-only from the host. ssh wants to write to +# known_hosts on first connect, so make a writable copy and point ssh at it. +# ssh still reads /root/.ssh/config by default, which sets Port 2222 for +# git.ghostguild.org and points IdentityFile at the deploy key. +mkdir -p /root/.ssh_tmp +chmod 700 /root/.ssh_tmp +if [ -f /root/.ssh/known_hosts ]; then + cp /root/.ssh/known_hosts /root/.ssh_tmp/known_hosts +else + touch /root/.ssh_tmp/known_hosts +fi +chmod 600 /root/.ssh_tmp/known_hosts +export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/root/.ssh_tmp/known_hosts" + +# Dump environment for cron jobs (crond doesn't inherit container env). +# Use single-quote escaping so values with spaces / special chars survive sourcing. +{ + env | while IFS='=' read -r k v; do + [ -z "$k" ] && continue + case "$k" in _|PWD|OLDPWD|SHLVL) continue ;; esac + esc=$(printf '%s' "$v" | sed "s/'/'\\\\''/g") + printf "export %s='%s'\n" "$k" "$esc" + done +} > /etc/environment.sh chmod 600 /etc/environment.sh echo "Cron jobs loaded:" diff --git a/docker-compose.yml b/docker-compose.yml index bd907e6..fa16ddf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,7 +80,9 @@ services: - ./content:/app/content - ./.git:/app/.git - /var/run/docker.sock:/var/run/docker.sock:ro - - ~/.ssh:/root/.ssh:ro + # Absolute path required: DokPloy does NOT expand ~ and would otherwise + # create a literal "~" directory under the deployment dir. + - /root/.ssh:/root/.ssh:ro - ./backups:/backups/outline env_file: - .env