fix: add detailed SSH permission fix logging for debugging

- Replace apply_ssh_permissions internals with _exec_and_log for full visibility
- Log every docker exec command, stdout, and stderr at DEBUG level
- After chown/chmod, run ls -la and stat to verify final state
- Log verified state at INFO level so users can see exactly what happened
- Update tests to mock subprocess.run instead of _run_in_container

Quality gates: pytest 236 passed (6 pre-existing), tsc --noEmit clean
This commit is contained in:
Alex Blank
2026-05-29 14:24:37 +02:00
parent d9632a3412
commit 68977b73be
3 changed files with 97 additions and 24 deletions
+77 -9
View File
@@ -104,6 +104,44 @@ def apply_mount_permissions(
return results
def _exec_and_log(
container_id: str,
command: list[str],
timeout: int,
description: str,
) -> str:
"""Run a docker exec command and log stdout/stderr for debugging."""
cmd = ["docker", "exec", "--user", "root", container_id] + command
logger.debug("[SSH-fix] %s: %s", description, " ".join(cmd))
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
)
except subprocess.TimeoutExpired:
raise PermissionFixError(
f"Command timed out after {timeout}s: {' '.join(command)}"
)
except FileNotFoundError:
raise PermissionFixError(f"Docker command not found: {' '.join(command)}")
stdout = result.stdout.strip()
stderr = result.stderr.strip()
if stdout:
logger.debug("[SSH-fix] %s stdout: %s", description, stdout)
if stderr:
logger.debug("[SSH-fix] %s stderr: %s", description, stderr)
if result.returncode != 0:
raise PermissionFixError(
f"Command failed (rc={result.returncode}): {stderr or '(no stderr)'}"
)
return stdout
def apply_ssh_permissions(
container_id: str,
ssh_target: str,
@@ -127,20 +165,24 @@ def apply_ssh_permissions(
"""
result: dict[str, Any] = {"success": True, "error": None}
try:
# Ensure directory is owned by the container user
_run_in_container(
# 1. Ensure directory is owned by the container user
_exec_and_log(
container_id,
["chown", "-R", f"{container_user}:{container_user}", ssh_target],
timeout,
"chown",
)
# Set directory permissions
_run_in_container(
# 2. Set directory permissions
_exec_and_log(
container_id,
["chmod", "700", ssh_target],
timeout,
"chmod-dir",
)
# Set private key permissions
_run_in_container(
# 3. Set private key permissions (id_ed25519, id_rsa, etc.)
_exec_and_log(
container_id,
[
"sh",
@@ -148,12 +190,38 @@ def apply_ssh_permissions(
f"find {ssh_target} -name 'id_*' -type f -exec chmod 600 {{}} +",
],
timeout,
"chmod-keys",
)
logger.debug(
"Applied SSH permissions for user %s on %s in container %s",
# 4. Verify final state
ls_output = _exec_and_log(
container_id,
["ls", "-la", ssh_target],
timeout,
"verify-ls",
)
stat_output = _exec_and_log(
container_id,
["stat", "-c", "%U:%G %a %n", ssh_target],
timeout,
"verify-stat-dir",
)
key_stat = _exec_and_log(
container_id,
["sh", "-c", f"stat -c '%U:%G %a %n' {ssh_target}/id_* 2>/dev/null || echo 'no id_* files found'"],
timeout,
"verify-stat-keys",
)
logger.info(
"SSH permissions fixed for container %s (user=%s, target=%s). "
"ls:\n%s\nstat-dir: %s\nstat-keys: %s",
container_id,
container_user,
ssh_target,
container_id,
ls_output,
stat_output,
key_stat,
)
except PermissionFixError as exc:
result["success"] = False