fix(deploy): give migrate the API's client-address settings, and say what Doctor checked #57

Merged
Zayin_Admin merged 2 commits from fix/doctor-client-address into main 2026-10-06 01:18:19 +00:00
3 changed files with 25 additions and 1 deletions
Showing only changes of commit 54ac6ab83f - Show all commits
+15
View File
@@ -958,6 +958,21 @@ describe("Ekklesia Doctor diagnostics", () => {
expect(report.result).toBe("ready-with-warnings"); expect(report.result).toBe("ready-with-warnings");
}); });
it("says whose client-address configuration it checked: this process's, not a running API's", async () => {
for (const clientAddress of [
undefined,
{ header: "x-forwarded-for", mode: "trusted-proxy" as const, trustedProxies: ["10.0.0.1"] },
{ header: "x-forwarded-for", mode: "trusted-proxy" as const, trustedProxies: ["bad"] },
]) {
const report = await diagnoseEkklesia(
{ ...options(), ...(clientAddress ? { clientAddress } : {}) },
dependencies(),
);
const details = check(report, "identity.client-address").details;
expect(details.some((detail) => detail.includes("environment Doctor runs with"))).toBe(true);
}
});
it("passes client-address configuration with an explicitly configured trusted-proxy mode", async () => { it("passes client-address configuration with an explicitly configured trusted-proxy mode", async () => {
const report = await diagnoseEkklesia( const report = await diagnoseEkklesia(
{ {
+5 -1
View File
@@ -555,12 +555,16 @@ grep -q 'TLS required with certificate and hostname verification (explicit priva
<<<"$doctor_output" || fail "Doctor did not report verify-full with the private CA." <<<"$doctor_output" || fail "Doctor did not report verify-full with the private CA."
grep -q '✓ Object storage reachable' <<<"$doctor_output" || grep -q '✓ Object storage reachable' <<<"$doctor_output" ||
fail "Doctor could not reach object storage over HTTPS." fail "Doctor could not reach object storage over HTTPS."
# Doctor runs as `migrate`; it must check the client-address configuration the API runs with, which
# behind the proxy is trusted-proxy mode, not the direct mode an unconfigured process reports.
grep -q 'Trusted-proxy client-address mode' <<<"$doctor_output" ||
fail "Doctor did not check the API's trusted-proxy client-address configuration."
for value in "$postgres_password" "$s3_secret_key" "$identity_secret"; do for value in "$postgres_password" "$s3_secret_key" "$identity_secret"; do
if grep -qF -- "$value" <<<"$doctor_output"; then if grep -qF -- "$value" <<<"$doctor_output"; then
fail "Doctor output contains a secret." fail "Doctor output contains a secret."
fi fi
done done
echo "ok Doctor: READY, verify-full with the private CA, storage reachable, no secret printed" echo "ok Doctor: READY, verify-full with the private CA, storage reachable, the API's client-address mode, no secret printed"
api_logs="$("${compose[@]}" logs --no-color api 2>&1)" api_logs="$("${compose[@]}" logs --no-color api 2>&1)"
for value in "$postgres_password" "$s3_secret_key" "$identity_secret" "$owner_password"; do for value in "$postgres_password" "$s3_secret_key" "$identity_secret" "$owner_password"; do
+5
View File
@@ -153,6 +153,11 @@ describe("reference deployment compose files", () => {
EKKLESIA_CLIENT_ADDRESS_MODE: "trusted-proxy", EKKLESIA_CLIENT_ADDRESS_MODE: "trusted-proxy",
EKKLESIA_CLIENT_ADDRESS_TRUSTED_PROXIES: `${proxyAddress}/32`, EKKLESIA_CLIENT_ADDRESS_TRUSTED_PROXIES: `${proxyAddress}/32`,
}); });
// Doctor runs as `migrate`. Given anything else, it validates a configuration the API is not
// running, and reports "Direct" for an installation that trusts its proxy.
expect(proxyOverlay.services?.migrate?.environment).toEqual(
proxyOverlay.services?.api?.environment,
);
expect(proxyOverlay.networks?.edge?.ipam?.config).toEqual([ expect(proxyOverlay.networks?.edge?.ipam?.config).toEqual([
{ {
ip_range: "${EKKLESIA_EDGE_DYNAMIC_RANGE:-10.249.250.0/25}", ip_range: "${EKKLESIA_EDGE_DYNAMIC_RANGE:-10.249.250.0/25}",