diff --git a/apps/docs/docs/integrations/whats-up-docker/index.mdx b/apps/docs/docs/integrations/whats-up-docker/index.mdx
index 31a0127f5..85707365e 100644
--- a/apps/docs/docs/integrations/whats-up-docker/index.mdx
+++ b/apps/docs/docs/integrations/whats-up-docker/index.mdx
@@ -24,12 +24,14 @@ The What's Up Docker integration lets Homarr connect to your [WUD](https://githu
:::info URL configuration
-Use the root URL of your WUD instance, for example `https://wud.example.com`. Homarr calls the `/api/app` and `/api/containers` endpoints under that URL automatically.
+Use the root URL of your WUD instance, for example `https://wud.example.com`. Homarr uses `/api/containers` under that URL for both connection testing and widget data.
:::
### Secrets
-WUD does not require authentication by default. If your instance is protected with [Basic Authentication](https://github.com/getwud/wud/blob/main/docs/configuration/authentications/basic/README.md), you can provide a username and password.
+WUD 9 requires authentication. Enter your WUD username and password in Homarr; the initial admin credentials configured with `WUD_AUTH_ADMIN_USER` and `WUD_AUTH_ADMIN_PASSWORD` work with Basic authentication. Older WUD versions without authentication can leave both fields empty.
+
+Credentials are sent to the configured URL over HTTP or HTTPS. Use HTTPS outside a trusted internal network.
{
expect(requestInit?.timeout).toBe(10_000);
});
- test("does not send credentials over a non-HTTPS URL", async () => {
+ test("sends configured Basic auth credentials over an HTTP URL", async () => {
mockFetch.mockResolvedValue(
new Response(JSON.stringify(sampleContainersResponse), {
status: 200,
@@ -209,7 +209,7 @@ describe("WudIntegration authentication", () => {
const integration = new WudIntegration({
id: "test-wud-http",
name: "Test WUD HTTP",
- url: "http://wud.example.com",
+ url: "http://wud:3000",
externalUrl: null,
decryptedSecrets: [
{ kind: "username", value: TEST_USERNAME },
@@ -221,7 +221,7 @@ describe("WudIntegration authentication", () => {
const [, requestInit] = mockFetch.mock.calls[0] ?? [];
const headers = (requestInit?.headers ?? {}) as Record;
- expect(headers.Authorization).toBeUndefined();
+ expect(headers.Authorization).toBe(`Basic ${Buffer.from(`${TEST_USERNAME}:${TEST_PASSWORD}`).toString("base64")}`);
});
});
@@ -238,15 +238,16 @@ describe("WudIntegration testing endpoint", () => {
fetchAsync: vi.fn().mockResolvedValue(response),
}) as unknown as IntegrationTestingInput;
- test("returns success when /api/app responds 200", async () => {
- const input = makeInput(new Response(JSON.stringify({ name: "wud", version: "5.0.0" }), { status: 200 }));
+ test("returns success when /api/containers responds 200", async () => {
+ const input = makeInput(new Response(JSON.stringify(sampleContainersResponse), { status: 200 }));
const result = await invokeTesting(createIntegration(), input);
expect(result.success).toBe(true);
+ expect(String(vi.mocked(input.fetchAsync).mock.calls[0]?.[0])).toBe(`${TEST_URL}/api/containers`);
});
- test("returns a status-code failure when /api/app responds non-OK", async () => {
+ test("returns a status-code failure when /api/containers responds non-OK", async () => {
const input = makeInput(new Response("unauthorized", { status: 401 }));
const result = await invokeTesting(createIntegration(), input);
@@ -255,7 +256,7 @@ describe("WudIntegration testing endpoint", () => {
});
test("passes the Basic auth header through to fetchAsync when configured", async () => {
- const response = new Response(JSON.stringify({ name: "wud", version: "5.0.0" }), { status: 200 });
+ const response = new Response(JSON.stringify(sampleContainersResponse), { status: 200 });
const input = makeInput(response);
await invokeTesting(createIntegrationWithBasicAuth(), input);
diff --git a/packages/integrations/src/wud/wud-integration.ts b/packages/integrations/src/wud/wud-integration.ts
index d7bdb49eb..05c6cc17a 100644
--- a/packages/integrations/src/wud/wud-integration.ts
+++ b/packages/integrations/src/wud/wud-integration.ts
@@ -14,7 +14,7 @@ const CONTAINERS_REQUEST_TIMEOUT_MS = 10_000;
export class WudIntegration extends Integration {
protected async testingAsync(input: IntegrationTestingInput): Promise {
- const response = await input.fetchAsync(this.url("/api/app"), {
+ const response = await input.fetchAsync(this.url("/api/containers"), {
headers: this.getAuthHeaders(),
});
@@ -23,10 +23,10 @@ export class WudIntegration extends Integration {
}
try {
- await response.json();
+ await parseWudContainersResponseAsync(response);
} catch (error) {
return TestConnectionError.ParseResult(
- new ParseError("Invalid WUD app response", {
+ new ParseError("Invalid WUD containers response", {
cause: error instanceof Error ? error : new Error(String(error)),
}),
);
@@ -55,10 +55,6 @@ export class WudIntegration extends Integration {
return undefined;
}
- if (this.url("/api/app").protocol !== "https:") {
- return undefined;
- }
-
const credentials = Buffer.from(`${this.getSecretValue("username")}:${this.getSecretValue("password")}`).toString(
"base64",
);