Fix cron container so daily wiki export actually runs
The cron has been silently failing every day since 2026-03-28. Four independent bugs were stacked: 1. cron/entrypoint.sh: env dump used `sed` to wrap each line in `export `, but values with spaces (e.g. GIT_SSH_COMMAND, OIDC_SCOPES) produced lines like `export GIT_SSH_COMMAND=ssh -o UserKnownHosts...` which `export` parses as a flag and aborts. busybox ash treats the builtin error as fatal, so `. /etc/environment.sh; script.sh` never reaches the script. Now single-quote each value with proper escaping. 2. cron/Dockerfile: NODE_PATH only works for CommonJS `require()`, not ESM `import`. The export script is `"type": "module"` and failed with "Cannot find package 'gray-matter'". Install deps at /app/node_modules instead — Node ESM walks up from /app/scripts and finds it there. 3. docker-compose.yml: `~/.ssh:/root/.ssh:ro` — DokPloy does NOT expand `~`, so it created a literal `~` directory inside the deployment dir and mounted that empty dir. The container had no SSH key. Use the absolute host path `/root/.ssh` instead. 4. cron/entrypoint.sh: even with the SSH key, `git push` would fail because the git remote is HTTPS and the host's git server runs on port 2222 (set in /root/.ssh/config). Add a `pushInsteadOf` rewrite so push uses SSH while DokPloy can keep fetching via HTTPS, and stop re-running ssh-keyscan against the wrong port — copy the host's known_hosts (which already has the :2222 entry) instead.
This commit is contained in:
parent
951c8807a8
commit
2085ad5103
3 changed files with 37 additions and 12 deletions
|
|
@ -11,10 +11,13 @@ RUN apk add --no-cache \
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install script dependencies at build time (into /opt so the ro volume mount doesn't shadow them)
|
# Install script dependencies at /app/node_modules. The /app/scripts dir is
|
||||||
COPY scripts/package*.json /opt/scripts-deps/
|
# a read-only host mount at runtime, so deps can't live inside it. Node ESM
|
||||||
RUN cd /opt/scripts-deps && npm install --omit=dev
|
# walks up from the importing file looking for node_modules — /app is the
|
||||||
ENV NODE_PATH=/opt/scripts-deps/node_modules
|
# 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/crontab /etc/crontabs/root
|
||||||
COPY cron/entrypoint.sh /entrypoint.sh
|
COPY cron/entrypoint.sh /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.email "wiki-bot@ghostguild.org"
|
||||||
git config --global user.name "Wiki Bot"
|
git config --global user.name "Wiki Bot"
|
||||||
|
|
||||||
# Add git remote host to known_hosts so SSH doesn't prompt
|
# The repo's origin is HTTPS (so DokPloy can fetch), but the cron pushes via
|
||||||
mkdir -p /root/.ssh_tmp
|
# SSH using the mounted deploy key. Rewrite the URL only for push operations.
|
||||||
cp /root/.ssh/* /root/.ssh_tmp/ 2>/dev/null || true
|
git config --global url."git@git.ghostguild.org:".pushInsteadOf "https://git.ghostguild.org/"
|
||||||
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"
|
|
||||||
|
|
||||||
# Dump environment for cron jobs (crond doesn't inherit container env)
|
# /root/.ssh is mounted read-only from the host. ssh wants to write to
|
||||||
env | grep -v '^_=' | sed 's/^\(.*\)$/export \1/' > /etc/environment.sh
|
# 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
|
chmod 600 /etc/environment.sh
|
||||||
|
|
||||||
echo "Cron jobs loaded:"
|
echo "Cron jobs loaded:"
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,9 @@ services:
|
||||||
- ./content:/app/content
|
- ./content:/app/content
|
||||||
- ./.git:/app/.git
|
- ./.git:/app/.git
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /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
|
- ./backups:/backups/outline
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue