runv-server

server tooling for runv.club
Log | Files | Refs | README

commit 271f19a446c3c0829612f2808c4b5467c9860017
parent 969e97c171b8d09d307e95071d89988642d53c18
Author: Pablo Murad <pablo@pablomurad.com>
Date:   Sat, 21 Mar 2026 16:14:17 -0300

fix

Diffstat:
Mpatches/yetgg.py | 6+++++-
Mscripts/admin/create_runv_user.py | 20+++++++++-----------
Mscripts/admin/setup_alt_protocols.py | 11+++++++----
Mscripts/docs/alt_protocols.md | 2+-
Mtools/tools.py | 22+++++++++++++---------
5 files changed, 35 insertions(+), 26 deletions(-)

diff --git a/patches/yetgg.py b/patches/yetgg.py @@ -83,7 +83,11 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace: ) p.add_argument("--dry-run", action="store_true", help="só simular") p.add_argument("--verbose", action="store_true", help="log detalhado") - p.add_argument("--force", action="store_true", help="sobrescrever modelos / symlinks (como setup_alt_protocols)") + p.add_argument( + "--force", + action="store_true", + help="sobrescrever gophermap / symlinks (como setup_alt_protocols); index.gmi existente mantém-se", + ) p.add_argument( "--users-json", type=Path, diff --git a/scripts/admin/create_runv_user.py b/scripts/admin/create_runv_user.py @@ -7,9 +7,10 @@ Contrato de provisionamento (ordem garantida após validação): 1. **Criar o usuário** — ``adduser --disabled-password``. 2. **Instalar a chave** — ``~/.ssh/authorized_keys`` com modos ``700`` / ``600``. 3. **Preparar public_html** — diretório ``755``, ``index.html`` estático ``644``. -4. **Preparar public_gopher / public_gemini** — ``gophermap`` e ``index.gmi`` modelo (não - sobrescreve sem ``--force-gopher`` / ``--force-gemini``); symlink Gemini em - ``/var/gemini/users/<user>`` quando o diretório existir. +4. **Preparar public_gopher / public_gemini** — ``gophermap`` modelo (não sobrescreve sem + ``--force-gopher``); ``index.gmi`` só é criado se ainda não existir (nunca substituído); + symlink em ``/var/gemini/users/<user>`` quando o diretório existir (``--force-gemini`` só + força reparação do symlink / conflitos). 5. **Copiar o skel** — o Debian copia ``/etc/skel`` para a home **durante** o passo 1; depois, após os diretórios públicos, o script acrescenta ``README.md`` runv (português), sem apagar o que veio do skel (use ``--force-readme`` para substituir). Prepare ``/etc/skel`` com ``tools.py`` @@ -522,7 +523,6 @@ def prepare_public_gemini( username: str, uid: int, gid: int, - force_gemini: bool, log: logging.Logger, ) -> None: d = home / "public_gemini" @@ -533,11 +533,9 @@ def prepare_public_gemini( except PermissionError as e: raise SystemProvisionError(f"não foi possível ajustar dono de {d}: {e}") from e idx = d / "index.gmi" - if idx.exists() and not force_gemini: - log.info("%s já existe; não sobrescrevendo (use --force-gemini)", idx) + if idx.exists(): + log.info("%s já existe; modelo não aplicado", idx) return - if idx.exists() and force_gemini: - log.warning("sobrescrevendo %s (--force-gemini)", idx) idx.write_text(default_gemini_index_gmi(username), encoding="utf-8") os.chmod(idx, 0o644) try: @@ -1172,7 +1170,7 @@ def interactive_fill(args: argparse.Namespace) -> None: default_no=True, ) args.force_gemini = prompt_yes_no( - "Se já existir ~/public_gemini/index.gmi, sobrescrever (--force-gemini)?", + "Forçar correção do symlink Gemini (/var/gemini/users) se estiver errado ou em conflito (--force-gemini)?", default_no=True, ) args.force_readme = prompt_yes_no( @@ -1270,7 +1268,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: p.add_argument( "--force-gemini", action="store_true", - help="sobrescrever ~/public_gemini/index.gmi e corrigir symlink em /var/gemini/users se necessário", + help="corrigir symlink em /var/gemini/users (e destinos em conflito); não sobrescreve index.gmi existente", ) p.add_argument( "--metadata-file", @@ -1477,7 +1475,7 @@ def main(argv: list[str] | None = None) -> int: log.info("=== fase 3b: public_gopher (gophermap) e public_gemini (index.gmi)") prepare_public_gopher(home, user, uid, gid, args.force_gopher, log) - prepare_public_gemini(home, user, uid, gid, args.force_gemini, log) + prepare_public_gemini(home, user, uid, gid, log) ensure_gemini_user_symlink(user, home, log, force=args.force_gemini) log.info("=== fase 4: README.md runv (após skel /etc/skel do adduser; texto em português)") diff --git a/scripts/admin/setup_alt_protocols.py b/scripts/admin/setup_alt_protocols.py @@ -494,9 +494,8 @@ def ensure_user_public_dirs( else: log.debug("gophermap já existe, mantido: %s", gmap) - if not xidx.exists() or force: - if xidx.exists() and force: - backup_if_exists(xidx, log, dry_run=False) + # index.gmi: nunca sobrescrever se já existir (--force não aplica ao modelo Gemini). + if not xidx.exists(): xidx.write_text( DEFAULT_USER_INDEX_GMI.format(username=username), encoding="utf-8", @@ -750,7 +749,11 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace: ) p.add_argument("--dry-run", action="store_true") p.add_argument("--verbose", action="store_true") - p.add_argument("--force", action="store_true", help="sobrescreve configs e ficheiros modelo com backup") + p.add_argument( + "--force", + action="store_true", + help="sobrescreve configs e ficheiros modelo com backup (index.gmi existente nunca é substituído)", + ) p.add_argument("--skip-install", action="store_true") p.add_argument("--skip-gopher", action="store_true") p.add_argument("--skip-gemini", action="store_true") diff --git a/scripts/docs/alt_protocols.md b/scripts/docs/alt_protocols.md @@ -119,7 +119,7 @@ sudo python3 scripts/admin/setup_alt_protocols.py --verbose |------|--------| | `--dry-run` | Simula; não grava (validação de root ignorada em alguns passos só se documentado). | | `--verbose` | Log detalhado. | -| `--force` | Sobrescreve configs de sistema (com backup com timestamp) e ficheiros modelo no backfill. Necessário para **regravar** `/etc/molly-brown/runv.club.conf` e remover o drop-in obsoleto **`50-runv-logs.conf`** (v0.05) ao migrar logs para `/var/lib/molly-brown/`. | +| `--force` | Sobrescreve configs de sistema (com backup com timestamp) e ficheiros modelo no backfill (exceto **`~/public_gemini/index.gmi`** se já existir). Necessário para **regravar** `/etc/molly-brown/runv.club.conf` e remover o drop-in obsoleto **`50-runv-logs.conf`** (v0.05) ao migrar logs para `/var/lib/molly-brown/`. | | `--skip-install` | Não corre `apt-get`. | | `--skip-gopher` / `--skip-gemini` | Ignora pacote, config e serviço desse protocolo. | | `--skip-firewall` | Não altera UFW. | diff --git a/tools/tools.py b/tools/tools.py @@ -329,15 +329,19 @@ def install_skel( log=log, summary=summary, ) - copy_one( - gemini_src, - gemini_dst, - 0o644, - force=force, - dry_run=dry_run, - log=log, - summary=summary, - ) + if gemini_dst.is_file(): + log.info("Destino já existe, mantido (index.gmi em skel): %s", gemini_dst) + summary.skipped.append(str(gemini_dst)) + else: + copy_one( + gemini_src, + gemini_dst, + 0o644, + force=force, + dry_run=dry_run, + log=log, + summary=summary, + ) if not dry_run: if gopher_dir.is_dir():