feat: add FRANCIS_HOST to connect to a standalone Francis runtime (#1768)

This commit is contained in:
Alessandro (Ale) Segala
2026-09-20 18:30:26 -07:00
committed by GitHub
parent 77a597dc4c
commit c57f703f21
35 changed files with 1124 additions and 130 deletions
+48
View File
@@ -0,0 +1,48 @@
# This Docker Compose file is used to set up the environment for the tests.
# It's the variant where Pocket ID does not embed the Francis actor runtime, but connects to a standalone one instead.
services:
lldap:
extends:
file: docker-compose.yml
service: lldap
scim-test-server:
extends:
file: docker-compose.yml
service: scim-test-server
francis-runtime:
# The version comes from the Francis dependency in backend/go.mod, so the runtime always matches the client Pocket ID is built with
# Set it with: echo "FRANCIS_VERSION=$(./francis-version.sh)" > .env
image: ghcr.io/italypaleale/francis:${FRANCIS_VERSION:?run ./francis-version.sh to set it, see CONTRIBUTING.md}
volumes:
- ./francis-config.yaml:/etc/francis/config.yaml:ro
# The image ships its own HEALTHCHECK, which probes the runtime over the loopback
# It's repeated here so Pocket ID can wait on it, and so a runtime that never comes up fails fast instead of after the default retries
healthcheck:
test: ["CMD", "/bin/francis", "healthcheck"]
interval: 2s
timeout: 5s
retries: 15
start_period: 5s
pocket-id:
extends:
file: docker-compose.yml
service: pocket-id
environment:
APP_ENV: test
ENCRYPTION_KEY: test-encryption-key
FILE_BACKEND: ${FILE_BACKEND}
# The runtime's port is UDP, since WebTransport runs over HTTP/3
EXPERIMENTAL_FRANCIS_HOST: francis-runtime:7400
# Must match "bootstrap.hostPSK" in francis-config.yaml
EXPERIMENTAL_FRANCIS_HOST_PSK: e2e-host-bootstrap-psk-0123456789
# EXPERIMENTAL_FRANCIS_CA is intentionally unset, so this exercises the same trust-on-first-use path an operator gets without it
# The cluster only exists inside this Compose network for the duration of the tests
#
# Peers reach actors placed on this host at ACTORS_HOST, which the runtime hands out, so it has to be the address other containers resolve rather than the default wildcard
ACTORS_HOST: pocket-id
depends_on:
francis-runtime:
condition: service_healthy
volumes:
pocket-id-test-data:
+27
View File
@@ -0,0 +1,27 @@
# Configuration for the standalone Francis runtime used by the "remote Francis" E2E variant.
# In that variant Pocket ID does not embed the actor runtime: it connects to this one instead, which owns the actor state, placement, and alarms.
# These secrets are fixed test values and must match the FRANCIS_HOST_PSK passed to Pocket ID in docker-compose-francis.yml.
# The WebTransport server runs over HTTP/3, so this port is UDP
bind: "0.0.0.0:7400"
# The runtime PSKs derive the cluster CA that signs every workload certificate
runtimePSKs:
- "e2e-runtime-psk-0123456789abcdef"
# Hosts prove they may join by presenting this pre-shared key
bootstrap:
method: psk
hostPSK: "e2e-host-bootstrap-psk-0123456789"
# The runtime owns its own SQLite store, which is separate from Pocket ID's database
# It lives in /tmp because the image runs as a non-root user (uid 65532) and that is the only world-writable directory in it
# The store only has to survive as long as the containers do, so there is nothing to persist beyond the test run
provider:
connectionString: "/tmp/francis.db"
# A single Pocket ID replica joins the cluster, matching the cap the embedded runtime applies when HA is off
maxHosts: 1
log:
level: debug
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
# Prints the Francis version Pocket ID depends on, formatted as the tag of the runtime's container image.
#
# The Go module is the single source of truth for the version: the standalone runtime the E2E tests run against
# has to be the same version as the client Pocket ID is built with, and pinning it in two places lets them drift.
#
# Usage, from this directory:
# echo "FRANCIS_VERSION=$(./francis-version.sh)" > .env
#
# This is a plain shell script rather than "go list" because the E2E workflow does not set up Go.
set -eu
go_mod="$(CDPATH='' cd -- "$(dirname -- "$0")/../../backend" && pwd)/go.mod"
if [ ! -f "$go_mod" ]; then
echo "francis-version.sh: cannot find $go_mod" >&2
exit 1
fi
# Module versions carry a leading "v" that container tags do not, so it is stripped
version=$(sed -n 's|^[[:space:]]*github\.com/italypaleale/francis v\([^[:space:]]*\).*|\1|p' "$go_mod" | head -n 1)
if [ -z "$version" ]; then
echo "francis-version.sh: no github.com/italypaleale/francis requirement found in $go_mod" >&2
exit 1
fi
printf '%s\n' "$version"