commit f1eb95d73819f3bdcbc8ef55e962d3129181f743
parent bb2734d8b2e952d6a4b42d919d7cc5de06dc8b8b
Author: Pablo Murad <pblmrd@gmail.com>
Date: Mon, 4 May 2026 02:13:25 -0300
fix permissions
Diffstat:
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: