eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
2.1 KiB
Python
53 lines
2.1 KiB
Python
"""Lee un secreto del gestor de contrasenas `pass` (passwordstore.org).
|
|
|
|
Ejecuta `pass show <path>` como subproceso (lista de args, nunca shell=True) y
|
|
devuelve la linea solicitada del secreto. Por convencion de pass, la primera
|
|
linea es la contrasena y las lineas siguientes son metadata (usuario, URL,
|
|
notas, etc.).
|
|
|
|
El valor devuelto es sensible: esta funcion NUNCA lo logea. El caller es
|
|
responsable de tratarlo como secreto (no imprimirlo, no persistirlo en claro).
|
|
"""
|
|
|
|
import subprocess
|
|
|
|
|
|
def pass_get_secret(path: str, *, line: int = 1, timeout_s: float = 10.0) -> dict:
|
|
"""Lee una linea de un secreto del password store (pass).
|
|
|
|
Args:
|
|
path: ruta del secreto dentro del store (p.ej. "gitea/dataforge-git-token").
|
|
Es el argumento que recibiria `pass show <path>`.
|
|
line: numero de linea a devolver, 1-indexed. line=1 (default) es la
|
|
primera linea = la contrasena por convencion de pass. line=N
|
|
devuelve la linea N para metadata multilinea.
|
|
timeout_s: timeout del subproceso en segundos.
|
|
|
|
Returns:
|
|
Dict. En exito: ``{"status": "ok", "value": str}`` con la linea pedida
|
|
sin el salto de linea final. En error (sin lanzar):
|
|
``{"status": "error", "error": str}`` para: pass no instalado, entry
|
|
inexistente / fallo de pass (returncode != 0), o linea fuera de rango.
|
|
"""
|
|
try:
|
|
proc = subprocess.run(
|
|
["pass", "show", path],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=timeout_s,
|
|
)
|
|
except FileNotFoundError:
|
|
return {"status": "error", "error": "pass not installed"}
|
|
except subprocess.TimeoutExpired:
|
|
return {"status": "error", "error": f"pass timed out after {timeout_s}s"}
|
|
|
|
if proc.returncode != 0:
|
|
return {"status": "error", "error": (proc.stderr or "").strip()}
|
|
|
|
# `pass show` termina con un salto de linea; splitlines lo absorbe.
|
|
lines = proc.stdout.splitlines()
|
|
if line < 1 or line > len(lines):
|
|
return {"status": "error", "error": f"line {line} out of range"}
|
|
|
|
return {"status": "ok", "value": lines[line - 1]}
|