mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-09 18:25:58 +03:00
Fix Playwright docker (#6206)
This commit is contained in:
@@ -91,17 +91,25 @@ When creating new scenario use the recorder to more easily identify elements
|
|||||||
This does not start the server, you will need to start it manually.
|
This does not start the server, you will need to start it manually.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx playwright codegen "http://127.0.0.1:8000"
|
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env up Vaultwarden
|
||||||
|
npx playwright codegen "http://127.0.0.1:8003"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Override web-vault
|
## Override web-vault
|
||||||
|
|
||||||
It is possible to change the `web-vault` used by referencing a different `bw_web_builds` commit.
|
It is possible to change the `web-vault` used by referencing a different `bw_web_builds` commit.
|
||||||
|
|
||||||
|
Simplest is to set and uncomment `PW_WV_REPO_URL` and `PW_WV_COMMIT_HASH` in the `test.env`.
|
||||||
|
Ensure that the image is built with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export PW_WV_REPO_URL=https://github.com/Timshel/oidc_web_builds.git
|
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env build Vaultwarden
|
||||||
export PW_WV_COMMIT_HASH=8707dc76df3f0cceef2be5bfae37bb29bd17fae6
|
```
|
||||||
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env build Playwright
|
|
||||||
|
You can check the result running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env up Vaultwarden
|
||||||
```
|
```
|
||||||
|
|
||||||
# OpenID Connect test setup
|
# OpenID Connect test setup
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
FROM playwright_oidc_vaultwarden_prebuilt AS prebuilt
|
FROM playwright_oidc_vaultwarden_prebuilt AS prebuilt
|
||||||
|
|
||||||
FROM node:22-bookworm AS build
|
FROM node:22-trixie AS build
|
||||||
|
|
||||||
ARG REPO_URL
|
ARG REPO_URL
|
||||||
ARG COMMIT_HASH
|
ARG COMMIT_HASH
|
||||||
@@ -14,7 +14,7 @@ COPY build.sh /build.sh
|
|||||||
RUN /build.sh
|
RUN /build.sh
|
||||||
|
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
FROM docker.io/library/debian:bookworm-slim
|
FROM docker.io/library/debian:trixie-slim
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ RUN mkdir /data && \
|
|||||||
--no-install-recommends \
|
--no-install-recommends \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
curl \
|
curl \
|
||||||
libmariadb-dev-compat \
|
libmariadb-dev \
|
||||||
libpq5 \
|
libpq5 \
|
||||||
openssl && \
|
openssl && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
@@ -16,7 +16,6 @@ if [[ ! -z "$REPO_URL" ]] && [[ ! -z "$COMMIT_HASH" ]] ; then
|
|||||||
|
|
||||||
export VAULT_VERSION=$(cat Dockerfile | grep "ARG VAULT_VERSION" | cut -d "=" -f2)
|
export VAULT_VERSION=$(cat Dockerfile | grep "ARG VAULT_VERSION" | cut -d "=" -f2)
|
||||||
./scripts/checkout_web_vault.sh
|
./scripts/checkout_web_vault.sh
|
||||||
./scripts/patch_web_vault.sh
|
|
||||||
./scripts/build_web_vault.sh
|
./scripts/build_web_vault.sh
|
||||||
printf '{"version":"%s"}' "$COMMIT_HASH" > ./web-vault/apps/web/build/vw-version.json
|
printf '{"version":"%s"}' "$COMMIT_HASH" > ./web-vault/apps/web/build/vw-version.json
|
||||||
|
|
||||||
|
@@ -26,9 +26,9 @@ export default defineConfig({
|
|||||||
* But short action/nav/expect timeouts to fail on specific step (raise locally if not enough).
|
* But short action/nav/expect timeouts to fail on specific step (raise locally if not enough).
|
||||||
*/
|
*/
|
||||||
timeout: 120 * 1000,
|
timeout: 120 * 1000,
|
||||||
actionTimeout: 10 * 1000,
|
actionTimeout: 20 * 1000,
|
||||||
navigationTimeout: 10 * 1000,
|
navigationTimeout: 20 * 1000,
|
||||||
expect: { timeout: 10 * 1000 },
|
expect: { timeout: 20 * 1000 },
|
||||||
|
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
|
@@ -66,6 +66,10 @@ SSO_CLIENT_SECRET=warden
|
|||||||
SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM}
|
SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM}
|
||||||
SSO_DEBUG_TOKENS=true
|
SSO_DEBUG_TOKENS=true
|
||||||
|
|
||||||
|
# Custom web-vault build
|
||||||
|
# PW_WV_REPO_URL=https://github.com/dani-garcia/bw_web_builds.git
|
||||||
|
# PW_WV_COMMIT_HASH=a5f5390895516bce2f48b7baadb6dc399e5fe75a
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Docker MariaDb container#
|
# Docker MariaDb container#
|
||||||
###########################
|
###########################
|
||||||
|
@@ -12,7 +12,7 @@ export async function logNewUser(
|
|||||||
test: Test,
|
test: Test,
|
||||||
page: Page,
|
page: Page,
|
||||||
user: { email: string, name: string, password: string },
|
user: { email: string, name: string, password: string },
|
||||||
options: { mailBuffer?: MailBuffer, override?: boolean } = {}
|
options: { mailBuffer?: MailBuffer } = {}
|
||||||
) {
|
) {
|
||||||
await test.step(`Create user ${user.name}`, async () => {
|
await test.step(`Create user ${user.name}`, async () => {
|
||||||
await page.context().clearCookies();
|
await page.context().clearCookies();
|
||||||
@@ -20,12 +20,8 @@ export async function logNewUser(
|
|||||||
await test.step('Landing page', async () => {
|
await test.step('Landing page', async () => {
|
||||||
await utils.cleanLanding(page);
|
await utils.cleanLanding(page);
|
||||||
|
|
||||||
if( options.override ) {
|
await page.locator("input[type=email].vw-email-sso").fill(user.email);
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
} else {
|
|
||||||
await page.getByLabel(/Email address/).fill(user.email);
|
|
||||||
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('Keycloak login', async () => {
|
await test.step('Keycloak login', async () => {
|
||||||
@@ -69,7 +65,6 @@ export async function logUser(
|
|||||||
user: { email: string, password: string },
|
user: { email: string, password: string },
|
||||||
options: {
|
options: {
|
||||||
mailBuffer ?: MailBuffer,
|
mailBuffer ?: MailBuffer,
|
||||||
override?: boolean,
|
|
||||||
totp?: OTPAuth.TOTP,
|
totp?: OTPAuth.TOTP,
|
||||||
mail2fa?: boolean,
|
mail2fa?: boolean,
|
||||||
} = {}
|
} = {}
|
||||||
@@ -82,12 +77,8 @@ export async function logUser(
|
|||||||
await test.step('Landing page', async () => {
|
await test.step('Landing page', async () => {
|
||||||
await utils.cleanLanding(page);
|
await utils.cleanLanding(page);
|
||||||
|
|
||||||
if( options.override ) {
|
await page.locator("input[type=email].vw-email-sso").fill(user.email);
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
} else {
|
|
||||||
await page.getByLabel(/Email address/).fill(user.email);
|
|
||||||
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('Keycloak login', async () => {
|
await test.step('Keycloak login', async () => {
|
||||||
|
@@ -29,8 +29,8 @@ test('SSO login', async ({ page }) => {
|
|||||||
test('Non SSO login', async ({ page }) => {
|
test('Non SSO login', async ({ page }) => {
|
||||||
// Landing page
|
// Landing page
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.getByLabel(/Email address/).fill(users.user1.email);
|
await page.locator("input[type=email].vw-email-sso").fill(users.user1.email);
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
await page.getByRole('button', { name: 'Other' }).click();
|
||||||
|
|
||||||
// Unlock page
|
// Unlock page
|
||||||
await page.getByLabel('Master password').fill(users.user1.password);
|
await page.getByLabel('Master password').fill(users.user1.password);
|
||||||
@@ -58,20 +58,12 @@ test('Non SSO login impossible', async ({ page, browser }, testInfo: TestInfo) =
|
|||||||
|
|
||||||
// Landing page
|
// Landing page
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.getByLabel(/Email address/).fill(users.user1.email);
|
|
||||||
|
|
||||||
// Check that SSO login is available
|
// Check that SSO login is available
|
||||||
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(1);
|
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(1);
|
||||||
|
|
||||||
await page.getByLabel(/Email address/).fill(users.user1.email);
|
// No Continue/Other
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
await expect(page.getByRole('button', { name: 'Other' })).toHaveCount(0);
|
||||||
|
|
||||||
// Unlock page
|
|
||||||
await page.getByLabel('Master password').fill(users.user1.password);
|
|
||||||
await page.getByRole('button', { name: 'Log in with master password' }).click();
|
|
||||||
|
|
||||||
// An error should appear
|
|
||||||
await page.getByLabel('SSO sign-in is required')
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -82,13 +74,12 @@ test('No SSO login', async ({ page }, testInfo: TestInfo) => {
|
|||||||
|
|
||||||
// Landing page
|
// Landing page
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.getByLabel(/Email address/).fill(users.user1.email);
|
|
||||||
|
|
||||||
// No SSO button (rely on a correct selector checked in previous test)
|
// No SSO button (rely on a correct selector checked in previous test)
|
||||||
await page.getByLabel('Master password');
|
|
||||||
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(0);
|
||||||
|
|
||||||
// Can continue to Master password
|
// Can continue to Master password
|
||||||
|
await page.getByLabel(/Email address/).fill(users.user1.email);
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
await page.getByRole('button', { name: 'Continue' }).click();
|
||||||
await expect(page.getByRole('button', { name: /Log in with master password/ })).toHaveCount(1);
|
await expect(page.getByRole('button', { name: 'Log in with master password' })).toHaveCount(1);
|
||||||
});
|
});
|
||||||
|
@@ -65,7 +65,7 @@ test('Enforce password policy', async ({ page }) => {
|
|||||||
await utils.logout(test, page, users.user1);
|
await utils.logout(test, page, users.user1);
|
||||||
|
|
||||||
await test.step(`Unlock trigger policy`, async () => {
|
await test.step(`Unlock trigger policy`, async () => {
|
||||||
await page.getByRole('textbox', { name: 'Email address (required)' }).fill(users.user1.email);
|
await page.locator("input[type=email].vw-email-sso").fill(users.user1.email);
|
||||||
await page.getByRole('button', { name: 'Use single sign-on' }).click();
|
await page.getByRole('button', { name: 'Use single sign-on' }).click();
|
||||||
|
|
||||||
await page.getByRole('textbox', { name: 'Master password (required)' }).fill(users.user1.password);
|
await page.getByRole('textbox', { name: 'Master password (required)' }).fill(users.user1.password);
|
||||||
|
Reference in New Issue
Block a user