Files
Oxicloud/tests/common/server.env
T
Edouard Vanbelle 5083eaeaba feat(config): add server config + can disable message-bus
- server now provide it's config via /api/config (possibility to feature flag)
- client use /api/config to enable / disable some features
- capability to disable the message bus, somme OPS may not want this feature and
  consume persistent connections from server (websocket):
  OXICLOUD_MESSAGEBUS_ENABLE (true by default)
2026-09-11 12:14:50 +02:00

250 lines
13 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Shared test-server environment variables.
# Sourced by tests/api/run.sh (shell) and read by tests/e2e/playwright.config.ts (Node).
# Do NOT include OXICLOUD_SERVER_PORT or OXICLOUD_STORAGE_PATH here —
# each test suite sets those to avoid port/directory conflicts.
DATABASE_URL=postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test
OXICLOUD_DB_CONNECTION_STRING=postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test
# `OXICLOUD_STATIC_PATH` intentionally NOT set — every remaining
# test suite either serves the built SvelteKit SPA from
# `static-dist/` (coverage suite via `start-server-spa.sh`) or
# doesn't need static assets at all (Hurl API / WebDAV / CalDAV
# suites). The legacy `./static` vanilla frontend was retired.
OXICLOUD_JWT_SECRET=test-secret-do-not-use-in-prod-minimum-32-chars
OXICLOUD_ENABLE_AUTH=true
OXICLOUD_ENABLE_TRASH=true
OXICLOUD_ENABLE_SEARCH=true
OXICLOUD_ENABLE_FILE_SHARING=true
OXICLOUD_ENABLE_MUSIC=true
# External file mounts — enabled so external_mounts.hurl can exercise the
# admin CRUD endpoints against a live mount registry.
OXICLOUD_ENABLE_EXTERNAL_MOUNTS=true
OXICLOUD_EXPOSE_SYSTEM_USERS=true
OXICLOUD_WOPI_ENABLED=true
# Fixed secret so the Hurl WOPI test can hand-craft valid access
# tokens with a known signing key. Prod deployments MUST override
# this to a random per-deployment value.
OXICLOUD_WOPI_SECRET=test-wopi-secret-do-not-use-in-prod-do-not-use-in-prod
# Discovery URL points at a black hole — VERB endpoints don't need
# discovery, and the WOPI Hurl suite deliberately does NOT touch
# `/api/wopi/editor-url` (the only path that would fetch it), so
# an unreachable URL keeps startup fast and hermetic.
OXICLOUD_WOPI_DISCOVERY_URL=http://127.0.0.1:9100/discovery.xml
OXICLOUD_WOPI_TOKEN_TTL_SECS=3600
OXICLOUD_OIDC_ENABLED=false
OXICLOUD_NEXTCLOUD_ENABLED=true
# Realtime WS keepalive interval (server-initiated protocol Ping).
# Production default is 30 s; tests drop it to 1 s so the S5 scenario
# in `tests/api/rt_bus_check.sh` can observe multiple keepalive frames
# arriving within a bounded (few-seconds) wall-clock. Only observed
# by `rt_ws_handler`, which reads it at each WS connect time.
OXICLOUD_MESSAGEBUS_KEEPALIVE_SECONDS=1
# Multi-entry storage config — see docs/plan/storage-multi-entry.md.
# `local_main` is FIRST so the boot fallback picks it when no active
# pointer is set in the DB yet (fresh test DB). Its root_dir falls
# back to $OXICLOUD_STORAGE_PATH (set in each test suite's run.sh).
# `s3_stub` is declared but never activated — it lets storage_config.hurl
# assert the entries table has more than one row without needing a
# real S3 backend.
OXICLOUD_STORAGE_ENTRIES=local_main,s3_stub,azurite,s3_blackhole
OXICLOUD_STORAGE_local_main_BACKEND=local
OXICLOUD_STORAGE_s3_stub_BACKEND=s3
OXICLOUD_STORAGE_s3_stub_S3_BUCKET=oxicloud-test-stub
OXICLOUD_STORAGE_s3_stub_S3_REGION=us-east-1
OXICLOUD_STORAGE_s3_stub_S3_ENDPOINT_URL=http://127.0.0.1:9999
OXICLOUD_STORAGE_s3_stub_S3_ACCESS_KEY=stub
OXICLOUD_STORAGE_s3_stub_S3_SECRET_KEY=stub
# `s3_blackhole` — an endpoint that never answers, as opposed to
# `s3_stub` above which refuses instantly.
#
# The distinction is the entire point. `127.0.0.1:9999` has nothing
# listening, so a connection is REFUSED: the kernel returns ECONNREFUSED
# immediately and the SDK reports an error straight away. That path was
# always handled. A test built on it would pass even with no timeout
# configured anywhere.
#
# `192.0.2.1` is TEST-NET-1 (RFC 5737), reserved for documentation and
# guaranteed not to be routed. A SYN to it goes unanswered — no RST, no
# ICMP — which is the failure that used to hang: with no bound, a socket
# read blocks until the OS abandons retransmission, on the order of
# fifteen minutes, during which the job is neither running nor failed.
#
# Declared but NEVER activated, like the other two. `backend_migration
# ?storage=s3_blackhole` reaches it explicitly.
#
# If a CI network answers 192.0.2.1 with ICMP unreachable, the failure
# degrades to the refused shape and `backend_migration_blackhole.hurl`
# still passes — both classify transient and both pause. It would simply
# stop pinning the timeout specifically. The assert on elapsed time in
# that file is what would notice.
OXICLOUD_STORAGE_s3_blackhole_BACKEND=s3
OXICLOUD_STORAGE_s3_blackhole_S3_BUCKET=oxicloud-blackhole
OXICLOUD_STORAGE_s3_blackhole_S3_REGION=us-east-1
OXICLOUD_STORAGE_s3_blackhole_S3_ENDPOINT_URL=http://192.0.2.1:9999
OXICLOUD_STORAGE_s3_blackhole_S3_ACCESS_KEY=blackhole
OXICLOUD_STORAGE_s3_blackhole_S3_SECRET_KEY=blackhole
# `azurite` — a REAL, reachable Azure backend, unlike `s3_stub` above.
# It points at the Azurite emulator started by spawn-db.sh, which speaks
# the actual Blob REST API, so this is the only way to exercise the Azure
# path without an account.
#
# Declared but NOT activated: the active backend stays local_main, so the
# rest of the suite is untouched. Tests reach it explicitly through
# `?storage=azurite` on the jobs that accept an entry name — which is
# exactly what that parameter was added for.
#
# The credentials are Azurite's fixed, publicly-documented development
# pair. They are in every Microsoft quickstart; nothing here is secret.
OXICLOUD_STORAGE_azurite_BACKEND=azure
OXICLOUD_STORAGE_azurite_AZURE_ACCOUNT_NAME=devstoreaccount1
OXICLOUD_STORAGE_azurite_AZURE_ACCOUNT_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
OXICLOUD_STORAGE_azurite_AZURE_CONTAINER=oxicloud-test
OXICLOUD_STORAGE_azurite_AZURE_ENDPOINT_URL=http://127.0.0.1:10000/devstoreaccount1
RUST_LOG="warn,audit=info,sqlx::migrate=info"
#RUST_LOG="warn,audit=info,oxicloud::quota=debug"
#RUST_LOG=debug
#RUST_LOG=info
# Per-chunk upload cap, exercised by chunked_upload_cap.hurl.
# 4 MiB: lets the existing grants.hurl single-chunk test (2.76 MB) pass
# under the cap, while the cap test sends a 5 MiB fixture to trigger 413.
OXICLOUD_CHUNK_MAX_BYTES=4194304
# Direct-PUT (non-chunked) cap, exercised by chunked_upload_cap.hurl.
# 4 MiB: same threshold as the chunked cap so the existing 5 MiB
# fixture (chunk-over-cap-5mb.bin) can prove BOTH caps with one
# generated file. All existing direct-PUT tests
# (test_dedup_webdav_multichunk.sh = 2.76 MB, _ref_count = ~66 KB,
# _nextcloud_put_blake3 = 32 B) stay safely under this cap.
OXICLOUD_DIRECT_PUT_MAX_BYTES=4194304
# Rate-limit ceiling for tests. `_MAX` alone isn't enough because
# the default `_WINDOW_SECS = 60` gives an effective rate of
# `MAX / 60` req/sec — a bursty Playwright suite (many workers,
# parallel logins + auto-refresh churn under DPoP required mode)
# overflows even at MAX=3600 (60 req/sec shared across the whole
# runner IP). Widening the window to 1 h means the same MAX is a
# 1-hour budget, well above what any single CI run consumes
# (< 5 min end-to-end). Applied to all three buckets so login /
# refresh / register all share the same generous test posture.
OXICLOUD_RATE_LIMIT_REFRESH_MAX=36000
OXICLOUD_RATE_LIMIT_REFRESH_WINDOW_SECS=3600
OXICLOUD_RATE_LIMIT_LOGIN_MAX=36000
OXICLOUD_RATE_LIMIT_LOGIN_WINDOW_SECS=3600
OXICLOUD_RATE_LIMIT_REGISTER_MAX=36000
OXICLOUD_RATE_LIMIT_REGISTER_WINDOW_SECS=3600
# The three above are keyed on the client IP. These two are keyed on the
# CALLER ID, which is why raising the three did nothing: the whole suite
# runs as a single `admin`, so every test shares one bucket.
#
# A 763-line e2e server log showed 81 × 429 — all on `http::api`, never
# `http::api::auth` — against the 60/min default for user-profile
# lookups. Admin views resolve an owner name per row, and the run
# creates 34 users, so a minute of tests clears 60 easily. Nothing
# failed, because the SPA degrades to an unresolved name, which is
# precisely why it went unnoticed: the noise would hide a real
# rate-limit regression.
#
# Same posture as above — a 1-hour window with a budget far beyond what
# one run consumes, rather than a raised per-minute rate that would
# still burst-trip.
OXICLOUD_RATE_LIMIT_USER_PROFILE_MAX=36000
OXICLOUD_RATE_LIMIT_USER_PROFILE_WINDOW_SECS=3600
OXICLOUD_RATE_LIMIT_DELTA_UPLOAD_MAX=36000
OXICLOUD_RATE_LIMIT_DELTA_UPLOAD_WINDOW_SECS=3600
# Magic-link / external-users flow (PR 9). The mock SMTP captures every
# outbound message in-process so external_users.hurl can retrieve the
# invitation body and follow the magic-link URL. The `SMTP_FROM` value
# is required so the mock can build a valid Message; host/port are
# irrelevant in mock mode but kept set for completeness.
OXICLOUD_SMTP_MOCK=true
OXICLOUD_SMTP_HOST=localhost
OXICLOUD_SMTP_PORT=25
OXICLOUD_SMTP_FROM='OxiCloud Tests <test@oxicloud.local>'
OXICLOUD_SMTP_TLS=none
OXICLOUD_ALLOW_EXTERNAL_USERS=true
# Public-registration email-domain allowlist. Exercised by
# `registration.hurl` step "off-domain rejection" (attempts to
# register with @nowhere.invalid and asserts 403
# `RegistrationDomainNotAllowed`). Contains BOTH `example.com` (Hurl
# fixtures use it — charlie@example.com etc.) AND `example.test` (E2E
# login.spec uses it — reg-*@example.test). Every legitimate test
# path stays inside the allowlist; the rejection test picks a domain
# outside it deliberately.
OXICLOUD_REGISTRATION_ALLOWED_EMAIL_DOMAINS=example.com,example.test
# Auth-policy vector. Enables the "magic-link login is allowed for
# accounts that also have a password" branch — required by
# auth_magic_link_login.hurl (alice has a password AND requests a
# magic-link login). Inert for every other test: `has_password`
# refusal only fires when the endpoint is called, and no other file
# calls `magic-link/send` for a password-holding account.
OXICLOUD_AUTH_POLICIES=permit_magic_link_for_password_users
OXICLOUD_AUTH_METHODS=password,magic_link
# Explicit pin — `--config` now overrides shell env (main.rs uses
# `from_filename_override`), but pinning here documents the intended
# test-env state. Flip to true for the deferred `tests/verify_email/`
# suite; leaving false here keeps every other suite on the "verified
# email not required" path (charlie's classic register+login etc.).
OXICLOUD_REQUIRE_VERIFIED_EMAIL=false
# PR 12 — magic-link rate-limit caps lowered so external_users.hurl can
# exercise the cap behaviour with a small, deterministic request count.
# Production defaults are 50 / 5 / 200 respectively (see example.env).
OXICLOUD_MAGIC_LINK_INVITE_PER_CALLER_PER_HOUR=3
OXICLOUD_MAGIC_LINK_SEND_PER_EMAIL_PER_HOUR=2
OXICLOUD_MAGIC_LINK_SEND_PER_IP_PER_HOUR=50
# permits IP spoofing for tests
OXICLOUD_TRUST_PROXY_CIDR=0.0.0.0/0
# ── OPAQUE aPAKE (Phase 0 substrate) ────────────────────────────────
# Boot the OPAQUE service in Migrate mode so every Hurl run exercises:
# 1. OpaqueConfig::from_env parsing all five OPAQUE env vars.
# 2. effective_mode(&auth) permitting Migrate because password IS in
# OXICLOUD_AUTH_METHODS above (would auto-downgrade to Off if we
# had disabled it — that path is unit-tested in
# common::config::tests::effective_mode_downgrades_to_off_...).
# 3. OpaqueService::from_config accepting a valid serialised setup.
# 4. AppState wiring populating `opaque_service = Some(_)`.
#
# Phase 0 has no wire-facing endpoints, so this only proves the
# substrate loads cleanly; opaque_substrate.hurl asserts the legacy
# /api/auth/login path remains intact and the future OPAQUE endpoints
# still 404 (they flip to 200 when Phase 1 lands).
#
# The SERVER_SETUP below is a throwaway keypair generated once for the
# test env — real deployments call `oxicloud opaque setup` and paste
# the output. Never reuse this value outside CI. Regenerate any time
# with:
# cargo run --bin oxicloud -- opaque setup
OXICLOUD_AUTH_OPAQUE_MODE=migrate
OXICLOUD_AUTH_OPAQUE_SERVER_SETUP="ZY4hAGa1MNyE7Ht+8ksLcyMmi/K2iJvxQly+DdfllUxjiH0+CjCt4hG6+9Y68jGet2L213dV0hajCbr4fXnekkWtUxqLr+butVHEksZ9NJRuZTvS6SMC73yf/yku4WUHT1NSRB2yHurAFmYn75D9wdA1VaXTuwgO/u5i1pvcsQs="
# Fast Argon2id — CI machines are underpowered vs production (256 MiB
# default would drag every test-scaffold future OPAQUE handshake in
# Phase 1+). Matches the params used in the round-trip unit test.
OXICLOUD_AUTH_OPAQUE_KSF_MEMORY_KIB=8
OXICLOUD_AUTH_OPAQUE_KSF_ITERATIONS=1
OXICLOUD_AUTH_OPAQUE_KSF_PARALLELISM=1
# DPoP (RFC 9449) — required mode surfaces every verifier /
# nonce / replay bug as a hard 401 (opportunistic would swallow
# some cases as warnings). Safe today because unbound sessions —
# `session.dpop_jkt IS NULL`, which is where the test admin's
# legacy-login lands — are still exempted at the middleware; the
# session-level enforcement flip is Gate 9. Once that arrives,
# every bind-time downgrade path also gets caught here without
# a config change. `dpop-hurl-helper` needs this on or the
# middleware is a pass-through and its scenarios all silently 200.
OXICLOUD_DPOP_MODE=required