runv-server

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

commit f1eb95d73819f3bdcbc8ef55e962d3129181f743
parent bb2734d8b2e952d6a4b42d919d7cc5de06dc8b8b
Author: Pablo Murad <pblmrd@gmail.com>
Date:   Mon,  4 May 2026 02:13:25 -0300

fix permissions

Diffstat:
Mdocs/13-troubleshooting.md | 1+
Mterminal/setup_entre.py | 68++++++++++++++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/docs/13-troubleshooting.md b/docs/13-troubleshooting.md @@ -35,5 +35,6 @@ ## SSH `entre` - Sessão fecha de imediato: rever PAM / modo `empty-password` / logs em `/var/log/runv/entre.log`. +- `/usr/bin/python3: can't open file '/opt/runv/terminal/entre_app.py': [Errno 13] Permission denied`: permissões da instalação em `/opt/runv/terminal` ficaram restritivas ou inconsistentes. Reexecute `sudo python3 REPO/terminal/setup_entre.py --yes` (com as mesmas flags de `--auth-mode` usadas em produção, se não forem as padrão) para reaplicar dono e modos: `/opt/runv` atravessável, árvore do módulo `root:entre` com diretórios `0750` e ficheiros `0640`. Próximo: [14-smoke-tests-and-validation.md](14-smoke-tests-and-validation.md). diff --git a/terminal/setup_entre.py b/terminal/setup_entre.py @@ -689,13 +689,54 @@ def install_config(dest: Path, *, dry_run: bool, force: bool) -> None: print(f"Instalado {cfg} (gen_config_toml a partir do example).") -def chmod_tree_templates(root: Path) -> None: - t = root / "templates" - if not t.is_dir(): - return - for p in t.rglob("*"): +def ensure_install_tree_permissions(root: Path, *, gid: int) -> None: + """Permissões determinísticas para o módulo usado pelo ForceCommand.""" + # /opt/runv precisa ser atravessável para o utilizador entre chegar ao módulo. + parent = root.parent + if parent.exists(): + try: + parent.chmod(0o755) + except OSError: + pass + + for dirpath, dirs, files in os.walk(root, followlinks=False): + current = Path(dirpath) + try: + os.chown(current, 0, gid) + current.chmod(0o750) + except OSError: + pass + + for name in dirs: + p = current / name + try: + os.chown(p, 0, gid, follow_symlinks=False) + p.chmod(0o750) + except OSError: + pass + + for name in files: + p = current / name + try: + os.chown(p, 0, gid, follow_symlinks=False) + p.chmod(0o640) + except OSError: + pass + + # O ForceCommand executa /usr/bin/python3 entre_app.py; Python precisa ler este ficheiro, + # e os módulos/templates adjacentes também precisam ser legíveis pelo utilizador entre. + for name in ( + "entre_app.py", + "entre_core.py", + "closed_app.py", + "close_entre.py", + "gen_config_toml.py", + "config.toml", + "config.example.toml", + ): + p = root / name if p.is_file(): - p.chmod(0o644) + p.chmod(0o640) def print_final_instructions( @@ -895,8 +936,6 @@ def main() -> int: ): force_cfg = True install_config(ir, dry_run=args.dry_run, force=force_cfg) - if not args.dry_run: - chmod_tree_templates(ir) if not args.dry_run: LOG_DIR.mkdir(parents=True, exist_ok=True) @@ -928,18 +967,7 @@ def main() -> int: log_path.chmod(0o640) if ir.exists(): - for root, dirs, files in os.walk(ir, followlinks=False): - for name in dirs + files: - p = Path(root) / name - try: - os.chown(p, uid, gid, follow_symlinks=False) - except OSError: - pass - try: - os.chown(ir, uid, gid) - except OSError: - pass - ir.chmod(0o750) + ensure_install_tree_permissions(ir, gid=gid) else: print("[dry-run] utilizador entre, fila, log e .ssh seriam garantidos (sem alterar sistema).") if args.auth_mode == AUTH_EMPTY: