fix: install.sh loop abort, ACME poll sudo gate, /static/ sub-paths
- install.sh: the traversal-chmod loop assigned _d but looped over the never-set $d; under set -u every fresh install aborted with "d: unbound variable" at that line. Loop over $_d. - acme collector: the self-heal normalize (sudo chmod g+rwX) now runs only when a no-sudo group-read-bit probe detects a lost bit — acme.sh re-hardens the tree 600 on every run, so the steady-state poll makes no sudo call. The group bit (not daemon readability) is what the two-user model keeps for the WebUI user. - lib.acme: new get_acme_home() accessor (ACME_HOME env, default data/acme), reused by _run_acme; _summarize_acme_output preserves a "Permission denied" line even when it is not among the final two, so the collector's actionable-error matcher keeps firing. - nginx template: emit location /static/ for any is_management path (not only '/'); the SPA references /static/... at the domain root regardless of the management backend path. - tests: probe, summarizer, and nginx-subpath cases in test_state.py, test_acme.py, test_nginx.py.
This commit is contained in:
@@ -277,3 +277,35 @@ class TestHasAutoRenew:
|
||||
with patch.object(acme, "_ACME_HOME", acme_dir):
|
||||
result = acme._has_auto_renew("nonexistent.com")
|
||||
assert result is False
|
||||
|
||||
|
||||
class TestSummarizeAcmeOutput:
|
||||
def test_last_two_lines(self):
|
||||
out = (
|
||||
"[2026-09-04] line one\n[2026-09-04] retry failed\n[2026-09-04] giving up\n"
|
||||
)
|
||||
assert acme._summarize_acme_output(out) == "retry failed; giving up"
|
||||
|
||||
def test_strips_timestamps_and_log_pointer(self):
|
||||
out = "[ts] work\nPlease check log file /x/acme.sh.log\n[ts] done\n"
|
||||
assert acme._summarize_acme_output(out) == "work; done"
|
||||
|
||||
def test_empty_returns_placeholder(self):
|
||||
assert acme._summarize_acme_output("") == "(no output)"
|
||||
|
||||
def test_preserves_permission_denied_outside_tail(self):
|
||||
out = (
|
||||
"[ts] starting\n"
|
||||
"[ts] /data/acme/account.conf: Permission denied\n"
|
||||
"[ts] step three\n"
|
||||
"[ts] step four\n"
|
||||
)
|
||||
summary = acme._summarize_acme_output(out)
|
||||
# The permission line is not among the final two, but the
|
||||
# actionable-error matcher (daemon/collectors/acme.py) keys off it.
|
||||
assert "account.conf: Permission denied" in summary
|
||||
assert summary.count("; ") == 2 # capped at three lines
|
||||
|
||||
def test_permission_denied_in_tail_not_duplicated(self):
|
||||
out = "[ts] ok\n[ts] account.conf: Permission denied\n"
|
||||
assert acme._summarize_acme_output(out) == "ok; account.conf: Permission denied"
|
||||
|
||||
Reference in New Issue
Block a user