Add Home Assistant Stelloauth app #1

Merged
dennis merged 17 commits from feat/home-assistant-stelloauth-addon into main 2026-09-24 20:19:49 +02:00
2 changed files with 100 additions and 2 deletions
Showing only changes of commit f231792fbb - Show all commits
+24
View File
@@ -100,3 +100,27 @@ def test_dockerfile_patches_parent_cloakserve_instead_of_copying_a_binary() -> N
def test_runtime_accepts_docker_port_unpublished_status() -> None:
runtime_test = (ROOT / "tests/test_runtime.sh").read_text(encoding="utf-8")
assert 'docker port "$container" 9222/tcp 2>/dev/null || true' in runtime_test
def test_runtime_requires_process_baseline_after_cdp_close_and_zero_stopped_pid() -> None:
runtime_test = (ROOT / "tests/test_runtime.sh").read_text(encoding="utf-8")
assert 'docker top "$container" -eo pid,args' in runtime_test
for prefix in ("first", "second"):
container = f"${prefix}_container"
baseline = (
f'{prefix}_baseline="$(capture_process_baseline "{container}")"'
)
ready_index = runtime_test.index(
f'wait_ready "{container}" "${prefix}_port"'
)
baseline_index = runtime_test.index(baseline)
close_index = runtime_test.index(
f'probe_and_close_cdp "{container}"', baseline_index
)
return_index = runtime_test.index(
f'assert_processes_return_to_baseline "{container}" "${prefix}_baseline"',
close_index,
)
assert ready_index < baseline_index < close_index < return_index
assert "{{.State.Pid}}" in runtime_test
assert '[ "$state" = "exited 0 0" ]' in runtime_test
+76 -2
View File
@@ -108,6 +108,76 @@ wait_ready() {
fail "$container did not become ready within 90 seconds"
}
normalized_process_commands() {
local container="$1"
local top_file="${tmp_dir}/${container}-processes.txt"
docker top "$container" -eo pid,args > "$top_file"
python3 - "$top_file" <<'PY'
import pathlib
import sys
commands = []
for raw_line in pathlib.Path(sys.argv[1]).read_text(encoding="utf-8").splitlines()[1:]:
fields = raw_line.split(maxsplit=1)
command = " ".join(fields[1].split()) if len(fields) == 2 else ""
lowered = command.lower()
if "/usr/local/bin/addon-supervisor" in command:
commands.append("addon-supervisor")
elif "/usr/local/bin/cloakserve" in command:
commands.append("cloakserve")
elif "/usr/local/bin/stelloauth" in command:
commands.append("stelloauth")
elif (
("/run/rosetta/rosetta" in lowered or "qemu-" in lowered)
and "chrome" not in lowered
and "chromium" not in lowered
and "headless_shell" not in lowered
):
continue
elif command:
commands.append(f"unexpected:{command}")
print("\n".join(sorted(commands)))
PY
}
capture_process_baseline() {
local container="$1"
local expected current
local deadline=$((SECONDS + 10))
expected=$'addon-supervisor\ncloakserve\nstelloauth'
while (( SECONDS < deadline )); do
current="$(normalized_process_commands "$container")"
if [ "$current" = "$expected" ]; then
printf '%s\n' "$current"
return
fi
sleep 0.25
done
printf 'expected startup process baseline:\n%s\ncurrent process commands:\n%s\n' \
"$expected" "$current" >&2
docker top "$container" >&2
fail "$container did not reach the expected startup process baseline"
}
assert_processes_return_to_baseline() {
local container="$1"
local baseline="$2"
local current
local deadline=$((SECONDS + 10))
while (( SECONDS < deadline )); do
current="$(normalized_process_commands "$container")"
if [ "$current" = "$baseline" ]; then
return
fi
sleep 0.25
done
printf 'expected process baseline after CDP close:\n%s\ncurrent process commands:\n%s\n' \
"$baseline" "$current" >&2
docker top "$container" >&2
fail "$container retained browser or profile processes after CDP close"
}
assert_loopback_cdp_listener() {
local container="$1"
local artifact="$2"
@@ -243,8 +313,8 @@ import sys
if float(sys.argv[1]) > 10.0:
raise SystemExit(f"container stop exceeded 10 seconds: {sys.argv[1]}")
PY
state="$(docker inspect --format '{{.State.Status}} {{.State.ExitCode}}' "$container")"
[ "$state" = "exited 0" ] || fail "$container state is $state, want exited 0"
state="$(docker inspect --format '{{.State.Status}} {{.State.ExitCode}} {{.State.Pid}}' "$container")"
[ "$state" = "exited 0 0" ] || fail "$container state is $state, want exited 0 with PID 0"
}
mkdir -p "$artifacts_dir"
@@ -262,9 +332,11 @@ fi
start_container "$first_container"
first_port="$(host_port "$first_container")"
wait_ready "$first_container" "$first_port"
first_baseline="$(capture_process_baseline "$first_container")"
assert_no_9222_mapping "$first_container"
assert_loopback_cdp_listener "$first_container" "${artifacts_dir}/runtime-proc-net-tcp.txt"
probe_and_close_cdp "$first_container"
assert_processes_return_to_baseline "$first_container" "$first_baseline"
post_invalid_worker "$first_port" "${artifacts_dir}/runtime-invalid-worker-response.json"
scan_logs "$first_container"
stop_and_assert "$first_container" "${artifacts_dir}/runtime-first-stop.txt"
@@ -273,9 +345,11 @@ scan_logs "$first_container"
start_container "$second_container"
second_port="$(host_port "$second_container")"
wait_ready "$second_container" "$second_port"
second_baseline="$(capture_process_baseline "$second_container")"
assert_no_9222_mapping "$second_container"
assert_loopback_cdp_listener "$second_container" "${artifacts_dir}/runtime-restart-proc-net-tcp.txt"
probe_and_close_cdp "$second_container"
assert_processes_return_to_baseline "$second_container" "$second_baseline"
sleep 5
docker stats --no-stream "$second_container" > "${artifacts_dir}/runtime-docker-stats.txt"