Migrate declarative configs to config/ dir and remove hardcoded paths
Replace all hardcoded /home/wall/vacuum-wall paths in lib/ with Path(__file__).resolve()
auto-discovery. Move config files from data/ to config/<subsystem>/config.json.
ACME now uses ACME_HOME env var and data/acme/ for cert storage. Systemd units
and sudoers use {{ USER_NAME }}, {{ PROJECT_DIR }}, {{ ACME_HOME }} Jinja2
template variables for install-time substitution. Remove sys.path.insert boot
strap from test files.
This commit is contained in:
+20
-13
@@ -2,7 +2,7 @@
|
||||
ACME certificate manager for Vacuum Wall.
|
||||
|
||||
Wraps acme.sh to issue, renew, and manage SSL/TLS certificates
|
||||
from Let's Encrypt (or other ACME providers). acme.sh runs as the
|
||||
from ACME providers such as ZeroSSL or Let's Encrypt. acme.sh runs as the
|
||||
vacuum-wall system user; nginx is reloaded via a deploy hook script.
|
||||
"""
|
||||
|
||||
@@ -16,16 +16,17 @@ from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PROJECT_DIR = Path(__file__).resolve().parent.parent
|
||||
_ACME_HOME = PROJECT_DIR / "data" / "acme"
|
||||
_DEPLOY_HOOK = str(PROJECT_DIR / "system" / "acme-deploy.sh")
|
||||
|
||||
_ACME_ENVIRON = {
|
||||
"HOME": str(Path.home()),
|
||||
"HOME": str(PROJECT_DIR),
|
||||
"PATH": os.environ.get(
|
||||
"PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
),
|
||||
}
|
||||
|
||||
PROJECT_DIR = Path("/home/wall/vacuum-wall")
|
||||
_DEPLOY_HOOK = str(PROJECT_DIR / "system" / "acme-deploy.sh")
|
||||
|
||||
|
||||
def _find_acme() -> str:
|
||||
"""Locate the acme.sh binary on the system.
|
||||
@@ -41,7 +42,7 @@ def _find_acme() -> str:
|
||||
FileNotFoundError: If acme.sh cannot be found.
|
||||
"""
|
||||
candidates = [
|
||||
Path.home() / ".acme.sh" / "acme.sh",
|
||||
_ACME_HOME / "acme.sh",
|
||||
Path("/usr/local/bin/acme.sh"),
|
||||
]
|
||||
|
||||
@@ -81,12 +82,15 @@ def _run_acme(args: list[str]) -> str:
|
||||
"""
|
||||
acme_bin = _find_acme()
|
||||
|
||||
# Check for ACME_HOME env var (set by systemd in production)
|
||||
acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME))
|
||||
|
||||
cmd: list[str] = [
|
||||
acme_bin,
|
||||
"--home",
|
||||
str(Path.home() / ".acme.sh"),
|
||||
acme_home_env,
|
||||
"--config-home",
|
||||
str(Path.home() / ".acme.sh"),
|
||||
acme_home_env,
|
||||
*args,
|
||||
]
|
||||
|
||||
@@ -131,7 +135,8 @@ def set_email(email: str) -> None:
|
||||
def get_email() -> str:
|
||||
"""Return the ACME contact email, or '' if none is configured."""
|
||||
try:
|
||||
account_conf = Path.home() / ".acme.sh" / "account.conf"
|
||||
acme_home = Path(os.environ.get("ACME_HOME", str(_ACME_HOME)))
|
||||
account_conf = acme_home / "account.conf"
|
||||
if account_conf.is_file():
|
||||
text = account_conf.read_text()
|
||||
match = re.search(r"^ACME_LEEMAIL=(.+)$", text, re.MULTILINE)
|
||||
@@ -246,7 +251,8 @@ def list_certs() -> list[dict]:
|
||||
certs: list[dict] = []
|
||||
|
||||
entries = _parse_list_output(raw)
|
||||
acme_home = Path.home() / ".acme.sh"
|
||||
acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME))
|
||||
acme_home = Path(acme_home_env)
|
||||
|
||||
for entry in entries:
|
||||
main = entry["main_domain"]
|
||||
@@ -393,7 +399,8 @@ def get_cert_paths(domain: str) -> dict:
|
||||
Returns:
|
||||
Dict with keys 'cert', 'key', 'ca', 'fullchain' mapped to paths.
|
||||
"""
|
||||
acme_home = str(Path.home() / ".acme.sh" / domain)
|
||||
acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME))
|
||||
acme_home = str(Path(acme_home_env) / domain)
|
||||
return {
|
||||
"cert": f"{acme_home}/{domain}.cert",
|
||||
"key": f"{acme_home}/{domain}.key",
|
||||
@@ -484,6 +491,6 @@ def _has_auto_renew(domain: str) -> bool:
|
||||
under ``~/.acme.sh/``; existence of this file means the systemd
|
||||
timer's ``--cron`` run will pick it up.
|
||||
"""
|
||||
acme_home = Path.home() / ".acme.sh"
|
||||
domain_conf = acme_home / f"{domain}.conf"
|
||||
acme_home_env = os.environ.get("ACME_HOME", str(_ACME_HOME))
|
||||
domain_conf = Path(acme_home_env) / f"{domain}.conf"
|
||||
return bool(domain_conf.is_file())
|
||||
|
||||
Reference in New Issue
Block a user