mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-09 18:25:58 +03:00
Compare commits
3 Commits
1f73630136
...
843c063649
Author | SHA1 | Date | |
---|---|---|---|
|
843c063649 | ||
|
550b670dba | ||
|
de808c5ad9 |
30
.github/workflows/release.yml
vendored
30
.github/workflows/release.yml
vendored
@@ -10,32 +10,14 @@ on:
|
|||||||
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
|
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
|
||||||
- '[1-2].[0-9]+.[0-9]+'
|
- '[1-2].[0-9]+.[0-9]+'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
# Apply concurrency control only on the upstream repo
|
||||||
|
group: ${{ github.repository == 'dani-garcia/vaultwarden' && format('{0}-{1}', github.workflow, github.ref) || github.run_id }}
|
||||||
|
# Don't cancel other runs when creating a tag
|
||||||
|
cancel-in-progress: ${{ github.ref_type == 'branch' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# https://github.com/marketplace/actions/skip-duplicate-actions
|
|
||||||
# Some checks to determine if we need to continue with building a new docker.
|
|
||||||
# We will skip this check if we are creating a tag, because that has the same hash as a previous run already.
|
|
||||||
skip_check:
|
|
||||||
# Only run this in the upstream repo and not on forks
|
|
||||||
if: ${{ github.repository == 'dani-garcia/vaultwarden' }}
|
|
||||||
name: Cancel older jobs when running
|
|
||||||
permissions:
|
|
||||||
actions: write
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
outputs:
|
|
||||||
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Skip Duplicates Actions
|
|
||||||
id: skip_check
|
|
||||||
uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
|
|
||||||
with:
|
|
||||||
cancel_others: 'true'
|
|
||||||
# Only run this when not creating a tag
|
|
||||||
if: ${{ github.ref_type == 'branch' }}
|
|
||||||
|
|
||||||
docker-build:
|
docker-build:
|
||||||
needs: skip_check
|
|
||||||
if: ${{ needs.skip_check.outputs.should_skip != 'true' && github.repository == 'dani-garcia/vaultwarden' }}
|
|
||||||
name: Build Vaultwarden containers
|
name: Build Vaultwarden containers
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
@@ -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();
|
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
||||||
} else {
|
|
||||||
await page.getByLabel(/Email address/).fill(user.email);
|
|
||||||
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();
|
await page.getByRole('button', { name: /Use single sign-on/ }).click();
|
||||||
} else {
|
|
||||||
await page.getByLabel(/Email address/).fill(user.email);
|
|
||||||
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);
|
||||||
|
@@ -639,9 +639,15 @@ make_config! {
|
|||||||
/// Timeout when acquiring database connection
|
/// Timeout when acquiring database connection
|
||||||
database_timeout: u64, false, def, 30;
|
database_timeout: u64, false, def, 30;
|
||||||
|
|
||||||
/// Database connection pool size
|
/// Timeout in seconds before idle connections to the database are closed
|
||||||
|
database_idle_timeout: u64, false, def, 600;
|
||||||
|
|
||||||
|
/// Database connection max pool size
|
||||||
database_max_conns: u32, false, def, 10;
|
database_max_conns: u32, false, def, 10;
|
||||||
|
|
||||||
|
/// Database connection min pool size
|
||||||
|
database_min_conns: u32, false, def, 2;
|
||||||
|
|
||||||
/// Database connection init |> SQL statements to run when creating a new database connection, mainly useful for connection-scoped pragmas. If empty, a database-specific default is used.
|
/// Database connection init |> SQL statements to run when creating a new database connection, mainly useful for connection-scoped pragmas. If empty, a database-specific default is used.
|
||||||
database_conn_init: String, false, def, String::new();
|
database_conn_init: String, false, def, String::new();
|
||||||
|
|
||||||
|
@@ -134,6 +134,8 @@ macro_rules! generate_connections {
|
|||||||
let manager = ConnectionManager::new(&url);
|
let manager = ConnectionManager::new(&url);
|
||||||
let pool = Pool::builder()
|
let pool = Pool::builder()
|
||||||
.max_size(CONFIG.database_max_conns())
|
.max_size(CONFIG.database_max_conns())
|
||||||
|
.min_idle(Some(CONFIG.database_min_conns()))
|
||||||
|
.idle_timeout(Some(Duration::from_secs(CONFIG.database_idle_timeout())))
|
||||||
.connection_timeout(Duration::from_secs(CONFIG.database_timeout()))
|
.connection_timeout(Duration::from_secs(CONFIG.database_timeout()))
|
||||||
.connection_customizer(Box::new(DbConnOptions{
|
.connection_customizer(Box::new(DbConnOptions{
|
||||||
init_stmts: conn_type.get_init_stmts()
|
init_stmts: conn_type.get_init_stmts()
|
||||||
|
Reference in New Issue
Block a user