fix(deploy): create /data/git/.ssh with 0700 before processgit starts#139
Conversation
Second papercut surfaced by the end-to-end install test on v0.1.2.
Init-config now successfully writes app.ini and Gitea boots past the
install wizard. It runs SQLite migrations, initializes the storage
modules, then dies with:
[F] code.gitea.io/gitea/services/asymkey.RewriteAllPublicKeys(ctx)
failed: open /data/git/.ssh/authorized_keys.tmp: permission
denied
RewriteAllPublicKeys writes an authorized_keys file containing all
registered SSH keys (zero on a fresh install — but it still writes
the empty file). The parent dir /data/git/.ssh must:
1. Exist
2. Be owned by the gitea user (uid 1000)
3. Have mode 0700 (SSH refuses to use it otherwise)
The standard gitea/gitea image's startup chain creates this. Our
custom /etc/s6/gitea/run override bypasses it (same s6-overlay v3
mismatch that broke env-var-to-app.ini conversion and necessitated
the init-config service in v0.1.2 — see #138).
Fix: add /data/git/.ssh to init-config's mkdir block and chmod 0700.
init-config runs as 1000:1000, so the dir ends up owned by the right
user automatically.
Two lines of substance, plus a doc comment explaining the SSH perms
requirement so this isn't surprising in three months.
Testing path: v0.1.3 release → fresh install → processgit should
become healthy on first boot.
Co-authored-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13d0ab7ff3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /data/git/repositories \ | ||
| /data/git/lfs | ||
| /data/git/lfs \ | ||
| /data/git/.ssh |
There was a problem hiding this comment.
Run SSH directory provisioning before lock short-circuit
This new /data/git/.ssh creation path only executes when app.ini is regenerated, but the script exits early whenever INSTALL_LOCK=true (deploy/bootstrap/init-config.sh lines 24–27). That means users upgrading from the broken v0.1.2 state (where app.ini already exists and startup failed on missing/invalid .ssh) will still skip these new lines and keep failing at Gitea startup. In practice, the fix works for fresh installs but not for the upgrade/recovery path it is intended to unblock.
Useful? React with 👍 / 👎.
fix(deploy): create
/data/git/.sshwith0700beforeprocessgitstartsWhat went wrong on v0.1.2
End-to-end install test on v0.1.2 (the install-wizard-skip fix from #138 is working — Gitea boots past the wizard, runs migrations, initializes storage), then dies with:
RewriteAllPublicKeyswrites anauthorized_keysfile containing all registered SSH keys (zero on a fresh install — but it still writes the empty file). The parent dir/data/git/.sshmust:0700(SSH refuses to use it otherwise)The standard
gitea/giteaimage's startup chain handles this. Our custom/etc/s6/gitea/runoverride bypasses it — the same s6-overlay v3 mismatch that broke env-var-to-app.ini and necessitated the init-config service in #138.Fix
Two lines of substance in
deploy/bootstrap/init-config.sh:Plus a 4-line doc comment so this isn't surprising six months from now when someone wonders why we chmod a directory.
init-configruns as1000:1000, so the dir ends up owned by the right user automatically — no chown needed.Why this wasn't in #138
Honestly: I didn't think of it. The pre-bootstrap mental model was "create the dirs Gitea writes config to" and I enumerated the obvious ones from the data tree. SSH auth-keys storage is a less-obvious one because Gitea writes there only on startup as a side effect of RewriteAllPublicKeys, not as part of any visible config path.
The end-to-end test is what surfaced this. This is the value of actually running the install — neither of these papercuts (install-wizard, ssh-dir) appeared in any of the unit tests or CI checks we've run. Every release we tag without a fresh-install validation pass is a potential bug parked in production.
What
init-config.shnow ensures (full list)Plus
/data/git/implicitly viamkdir -p.Could there be more missing dirs?
Maybe. Gitea creates
/app/gitea/data/{repo-archive,packages,actions_log,actions_artifacts}lazily at startup — those work because/app/gitea/data/is writable. The next install attempt will tell us if anything else needs to be pre-provisioned. If so, we add it in v0.1.4. The pattern is now established: pre-bootstrap container, idempotent, owned by 1000:1000.After merge
Tag
v0.1.3against new main HEAD. Operator pulls v0.1.3's compose, runsdocker compose up -d, and processgit should becomehealthyon its own.