Dalidou Claude's second re-deploy (commit b492f5f) reported one
remaining friction point: the app dir was root-owned from the
previous manual-workaround deploy (when ALTER TABLE was run as
root to work around the schema init bug), so deploy.sh's git
fetch/reset hit a permission wall. They worked around it with
a one-shot docker run chown, but the script itself produced
cryptic git errors before that, so the fix wasn't obvious until
after the fact.
This commit adds a permission pre-flight check that runs BEFORE
any git operations and exits cleanly with an explicit remediation
message instead of letting git produce half-state on partial
failure.
The check:
1. Reads the current owner of the app dir via `stat -c '%U:%G'`
2. Reports the current user via `id -un` / `id -u:id -g`
3. Attempts to create a throwaway marker file in the app dir
4. If the marker write fails, prints three distinct remediation
commands covering the common environments:
a. sudo chown -R 1000:1000 $APP_DIR (if passwordless sudo)
b. sudo bash $0 (if running deploy.sh itself as root works)
c. docker run --rm -v $APP_DIR:/app alpine chown -R ...
(what Dalidou Claude actually did on 2026-04-08)
5. Exits with code 5 so CI / automation can distinguish "no
permission" from other deploy failures
Dry-run mode skips the check (nothing is mutated in dry-run).
A brief WARNING is also printed early if the app dir exists but
doesn't appear writable, before the fatal check — this gives
operators a heads-up even in the happy-path case.
Syntax check: bash -n passes.
Full suite: 216 passing (unchanged; no code changes to the app).
What this commit does NOT do
----------------------------
- Does NOT automatically fix permissions. chown needs root and
we don't want deploy.sh to escalate silently. The operator
runs one of the three remediation commands manually.
- Does NOT check permissions on nested files (like .git/config)
individually. The marker-file test on the app dir root is the
cheapest proxy that catches the common case (root-owned dir
tree after a previous sudo-based operation).
- Does NOT change behavior on first-time deploys where the app
dir doesn't exist yet. The check is gated on `-d $APP_DIR`.