Run the Bitwarden SDK's live end-to-end tests against Vaultwarden (#7953)

* Add a test seeder behind the unsafe_test_mode feature

For the end-to-end tests: with the feature, /test/seeder answers the calls the
SDK's live tests make to a seeder API (POST /seed with SingleUserScene or
TestVectorUserScene, DELETE /seed/<playId>), behind HTTP basic auth from
TEST_SEEDER_USERNAME and TEST_SEEDER_PASSWORD, and 404 without them.

It creates accounts without any checks, so no release build has the feature.
CI builds and tests it with sqlite.

* Run the SDK live tests against the test seeder

tools/sdk-live-tests/run.sh builds the server with unsafe_test_mode and runs
the live tests of the SDK's e2e/wasm suite. For SDK versions whose tests log in
to one given account, each user test vector with a master password is seeded
with its vault on a fresh server; for versions that seed their own accounts,
the tests get the seeder's address. Every vector runs, then a summary.

The workflow runs it by hand, and on changes to the seeder or the runner.

* Run the SDK live tests daily

* Test the published SDK package by default in the SDK live tests
This commit is contained in:
Daniel García authored and GitHub committed 2026-11-13 19:48:10 +01:00
1 parent 730048e3c6
commit d2d1294098
12 files changed
+997 -1

No files matched your search

+17
View File
@@ -158,6 +158,13 @@ jobs:
if: ${{ !cancelled() }}
run: |
cargo test --profile ci --features postgresql
# The test seeder only exists with this feature, which no release build has
- name: "test features: sqlite,unsafe_test_mode"
id: test_unsafe_test_mode
if: ${{ !cancelled() }}
run: |
cargo test --profile ci --features sqlite,unsafe_test_mode
# End Run cargo tests
@@ -167,6 +174,12 @@ jobs:
if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }}
run: |
cargo clippy --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3
- name: "clippy features: sqlite,unsafe_test_mode"
id: clippy_unsafe_test_mode
if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }}
run: |
cargo clippy --profile ci --features sqlite,unsafe_test_mode
# End Run cargo clippy
@@ -190,7 +203,9 @@ jobs:
TEST_SQLITE: ${{ steps.test_sqlite.outcome }}
TEST_MYSQL: ${{ steps.test_mysql.outcome }}
TEST_POSTGRESQL: ${{ steps.test_postgresql.outcome }}
TEST_UNSAFE_TEST_MODE: ${{ steps.test_unsafe_test_mode.outcome }}
CLIPPY: ${{ steps.clippy.outcome }}
CLIPPY_UNSAFE_TEST_MODE: ${{ steps.clippy_unsafe_test_mode.outcome }}
FMT: ${{ steps.formatting.outcome }}
run: |
echo "### :x: Checks Failed!" >> "${GITHUB_STEP_SUMMARY}"
@@ -203,7 +218,9 @@ jobs:
echo "|test (sqlite)|${TEST_SQLITE}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|test (mysql)|${TEST_MYSQL}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|test (postgresql)|${TEST_POSTGRESQL}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|test (sqlite,unsafe_test_mode)|${TEST_UNSAFE_TEST_MODE}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|clippy (sqlite,mysql,postgresql,enable_mimalloc,s3)|${CLIPPY}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|clippy (sqlite,unsafe_test_mode)|${CLIPPY_UNSAFE_TEST_MODE}|" >> "${GITHUB_STEP_SUMMARY}"
echo "|fmt|${FMT}|" >> "${GITHUB_STEP_SUMMARY}"
echo "" >> "${GITHUB_STEP_SUMMARY}"
echo "Please check the failed jobs and fix where needed." >> "${GITHUB_STEP_SUMMARY}"
+163
View File
@@ -0,0 +1,163 @@
name: SDK live tests
permissions: {}
# Runs the live-server end-to-end tests of bitwarden/sdk-internal against this branch, see tools/sdk-live-tests/run.sh.
# By default it tests the latest @bitwarden/sdk-internal on npm, which the SDK publishes for every commit to its main
# branch, with the e2e tests from that commit. A manual run can name an npm version instead, or a branch, tag or commit
# to build the SDK from. It runs daily, by hand, and on changes to the test seeder or the runner.
on:
schedule:
# 04:15 UTC, off the top of the hour, when GitHub may delay or drop scheduled runs
- cron: "15 4 * * *"
workflow_dispatch:
inputs:
sdk_npm_version:
description: "Version of @bitwarden/sdk-internal on npm to test (empty for the latest)"
required: false
default: ""
sdk_ref:
description: "Or a branch, tag or commit of bitwarden/sdk-internal to build and test (slower)"
required: false
default: ""
pull_request:
paths:
- ".github/workflows/sdk-live-tests.yml"
- "src/api/test_seeder.rs"
- "tools/sdk-live-tests/**"
defaults:
run:
shell: bash
jobs:
sdk-live-tests:
name: SDK live tests
runs-on: ubuntu-24.04
timeout-minutes: 90
env:
# Less to compile and link, and a smaller cache. Panics still show file and line.
CARGO_PROFILE_DEV_DEBUG: "0"
steps:
- name: "Install dependencies Ubuntu"
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential libssl-dev pkg-config
- name: "Checkout"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# A published package (npm) or a build from a git ref (git), and the sdk-internal commit to check out
- name: "Pick the SDK"
id: sdk
env:
NPM_VERSION: ${{ inputs.sdk_npm_version }}
GIT_REF: ${{ inputs.sdk_ref }}
run: |
if [[ -n "${NPM_VERSION}" && -n "${GIT_REF}" ]]; then
echo "::error::Give an npm version or a git ref, not both"
exit 1
fi
if [[ -n "${GIT_REF}" ]]; then
{
echo "source=git"
echo "ref=${GIT_REF}"
} >> "${GITHUB_OUTPUT}"
echo "SDK: bitwarden/sdk-internal \`${GIT_REF}\`, built from source" >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
spec="${NPM_VERSION:-latest}"
if [[ ! "${spec}" =~ ^[0-9A-Za-z.+-]+$ ]]; then
echo "::error::That is not an npm version or tag"
exit 1
fi
manifest="$(curl -fsS --retry 3 "https://registry.npmjs.org/@bitwarden%2Fsdk-internal/${spec}")"
version="$(jq -r .version <<< "${manifest}")"
commit="$(jq -r .gitHead <<< "${manifest}")"
if [[ ! "${commit}" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::@bitwarden/sdk-internal@${version} doesn't name the commit it was built from"
exit 1
fi
{
echo "source=npm"
echo "version=${version}"
echo "ref=${commit}"
} >> "${GITHUB_OUTPUT}"
echo "SDK: @bitwarden/sdk-internal ${version} from npm, e2e tests at ${commit}" >> "${GITHUB_STEP_SUMMARY}"
- name: "Checkout sdk-internal"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: bitwarden/sdk-internal
ref: ${{ steps.sdk.outputs.ref }}
path: sdk-internal
persist-credentials: false
# Each checkout pins its own toolchain in rust-toolchain.toml. The SDK's is only needed to build it.
- name: "Install toolchains"
env:
SDK_SOURCE: ${{ steps.sdk.outputs.source }}
run: |
rustup toolchain install
if [[ "${SDK_SOURCE}" == git ]]; then
cd sdk-internal
rustup toolchain install
rustup target add wasm32-unknown-unknown
rustup component add rust-src
fi
# One cache per SDK source, so that neither restores the other's
- name: "Cache Rust builds"
if: ${{ steps.sdk.outputs.source == 'npm' }}
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
key: sdk-live-tests-npm
add-job-id-key: false
workspaces: ". -> target"
- name: "Cache Rust builds (with the SDK)"
if: ${{ steps.sdk.outputs.source == 'git' }}
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
key: sdk-live-tests-sdk-build
add-job-id-key: false
workspaces: |
. -> target
sdk-internal -> target
- name: "Setup Node"
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: sdk-internal/.nvmrc
# Where the SDK's build would put it
- name: "Download the SDK package"
if: ${{ steps.sdk.outputs.source == 'npm' }}
env:
SDK_VERSION: ${{ steps.sdk.outputs.version }}
SDK_COMMIT: ${{ steps.sdk.outputs.ref }}
run: |
# npm checks the tarball against the registry's checksum
tarball="$(npm pack "@bitwarden/sdk-internal@${SDK_VERSION}" --pack-destination "${RUNNER_TEMP}" --json | jq -r '.[0].filename')"
package_dir=sdk-internal/crates/bitwarden-wasm-internal/npm
tar -xzf "${RUNNER_TEMP}/${tarball}" --strip-components=1 -C "${package_dir}"
if [[ "$(cat "${package_dir}/VERSION")" != "${SDK_COMMIT}" ]]; then
echo "::error::The package's VERSION doesn't match its commit ${SDK_COMMIT}"
exit 1
fi
- name: "Run the SDK live tests"
env:
SDK_SOURCE: ${{ steps.sdk.outputs.source }}
run: |
args=(--sdk-dir sdk-internal)
if [[ "${SDK_SOURCE}" == npm ]]; then
args+=(--skip-sdk-build)
fi
tools/sdk-live-tests/run.sh "${args[@]}"
- name: "Upload logs"
if: ${{ !cancelled() }}
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sdk-live-tests-logs
path: target/sdk-live-tests/**/*.log