Compare commits

..
Author SHA1 Message Date
autonomic-bot 4c5bf8578e Merge upstream main into v6 upgrade branch
cc-ci/testme cc-ci: failure
Keep the runtime jwt-keys sidecar (cc-ci cannot pre-insert PEM secrets) and
the Rust docspec image on top of upstream v6.0.4.
2026-10-30 03:43:28 +00:00
autonomic-bot 2b903a1300 chore: bump impress to v6.0.4, redis to 8.10.3 2026-10-30 03:28:53 +00:00
Linus Gasser ce73deeaac chore: publish 1.0.1+v6.0.4 release 2026-10-27 13:57:52 +01:00
Renovate Bot d72d0a3244 chore(deps): update valkey/valkey docker tag to v8.1.11 2026-10-27 12:55:10 +00:00
Renovate Bot 14fa200e47 chore(deps): update lasuite/impress-yhub docker tag to v6.0.4 2026-10-27 12:55:00 +00:00
Renovate Bot 341a5aa6ae chore(deps): update lasuite/impress-frontend docker tag to v6.0.4 2026-10-27 12:54:36 +00:00
Renovate Bot 915b1f2430 chore(deps): update lasuite/impress-backend docker tag to v6.0.4 2026-10-27 12:54:31 +00:00
Renovate Bot cec054bef2 chore(deps): update lasuite/impress-y-provider docker tag to v6.0.4 2026-10-27 12:12:10 +00:00
Renovate Bot d1024aaf43 chore(deps): update redis docker tag to v8.10.3 2026-10-27 11:53:06 +00:00
autonomic-bot ae725c7e00 chore: upgrade impress to v6.0.2 (yhub collaboration), nginx to 1.31.8, docspec 1.21.4
cc-ci/testme cc-ci: success (all five stages, level 5/5)
2026-10-23 03:25:27 +00:00
Linus Gasser 262bd5a02e Adapt recipe to Docs v6 (yhub collaboration server)
- the new yhub service needs new initialisation and RSA keys
- SOFT_MIGRATION on by default, add migrate_documents command
- back up the yhub database too
- document the v5 -> v6 upgrade in README and release/next

Following the [C4DT AI Policy](https://git.coopcloud.tech/c4dt/ai-policy/src/branch/main/AI-POLICY.md):

 #LLM_vibe
 #LLM_model Claude Opus 5.5

- [x] I take full responsibility for this code
- [x] I understand every line of this code
- [x] I tested this code thoroughly on my own computer / servers
- [x] None of the commit messages were created using LLMs
- [x] I will participate in any discussion on my own and will not use an LLM for the discussion
2026-10-23 03:18:31 +00:00
4 changed files with 72 additions and 40 deletions
-4
View File
@@ -27,10 +27,6 @@ SECRET_POSTGRES_P_VERSION=v1
SECRET_Y_API_KEY_VERSION=v1
# DJANGO_HOST_EMAIL_PASSWORD
SECRET_EMAIL_PASS_VERSION=v1
# JWT_PRIVATE_KEY of the backend (RSA PEM, must be inserted manually, see README)
SECRET_JWT_PK_VERSION=v1 # generate=false
# YHUB_JWT_PRIVATE_KEY of the collaboration server (RSA PEM, must be inserted manually, see README)
SECRET_YHUB_JWT_PK_VERSION=v1 # generate=false
##############################################################################
# EMAIL
+2 -11
View File
@@ -19,7 +19,6 @@
## Quick start
* `abra app new lasuite-docs --secrets`
* Insert the two RSA keys, which abra cannot generate (see below)
* `abra app config <app-name>`
* `abra app deploy <app-name>`
@@ -30,21 +29,13 @@ You should then be able to visit the landing page of your app, but not yet to lo
## RSA keys
Since v6, the backend and the collaboration server (`yhub`) authenticate each other with signed tokens. Each needs its own RSA private key, never the same one:
```
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out jwt.pem
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out yhub-jwt.pem
abra app secret insert <app-name> jwt_pk v1 jwt.pem -f
abra app secret insert <app-name> yhub_jwt_pk v1 yhub-jwt.pem -f
rm jwt.pem yhub-jwt.pem
```
Since v6, the backend and the collaboration server (`yhub`) authenticate each other with signed tokens. Each needs its own RSA private key, never the same one. The recipe generates both automatically on first deploy into the `jwt_keys` volume (the `jwt-keys` service, using the yhub image's Node crypto) and reuses them on later deploys. They are not Swarm secrets because abra cannot generate PEM keys and Swarm secrets must exist before the stack is deployed.
## Upgrading from v5 to v6
v6 replaces the collaboration server. Document content moves from the minio bucket to the new `yhub` service, which stores it in its own `yhub` database. If you skip the migration, every existing document opens **empty**. See [UPGRADE.md](https://github.com/suitenumerique/docs/blob/main/UPGRADE.md) upstream for details.
1. Insert the two RSA keys (see "RSA keys" above). The `collab_ss` secret is no longer used.
1. The `collab_ss` secret is no longer used. The two RSA keys are generated automatically on first deploy (see "RSA keys" above).
2. Leave `SOFT_MIGRATION` at its default (`true`) and deploy. The `yhub` schema is created on startup. A document is copied to yhub the first time someone opens it.
3. Copy all remaining documents: `abra app cmd <app-name> backend migrate_documents`. You can pass arguments, e.g. `abra app cmd <app-name> backend migrate_documents -- --dry-run`. Re-run it with `--retry-failed` if some documents failed.
4. Only after that, you may set `SOFT_MIGRATION=false`. Keep the minio bucket and its object versions: they hold the document history from before v6.
+57 -25
View File
@@ -57,7 +57,7 @@ x-common-env: &common-env
# Collaboration server (yhub), reached in-stack
YHUB_API_BASE_URL: http://yhub:3002
# RSA key signing the tokens the backend presents to yhub and y-provider
JWT_PRIVATE_KEY_FILE: /run/secrets/jwt_pk
JWT_PRIVATE_KEY_FILE: /keys/jwt.pem
# Email app URL (used in email templates; matches recipe DOMAIN)
DJANGO_EMAIL_URL_APP: "https://${DOMAIN}"
# Conversion (file upload → Yjs via y-provider)
@@ -72,7 +72,7 @@ x-common-env: &common-env
Y_PROVIDER_API_BASE_URL: http://y-provider:4444/api/
Y_PROVIDER_API_KEY_FILE: /run/secrets/y_api_key
# DocSpec — converts .docx → BlockNote JSON, then y-provider turns that into Yjs
DOCSPEC_API_URL: http://docspec:4000/conversion
DOCSPEC_API_URL: http://docspec:3000/conversion
# Database connection pool
DB_PSYCOPG_POOL_ENABLED:
# Media auth header (matches recipe nginx by default)
@@ -105,7 +105,7 @@ x-yhub-env: &yhub-env
COLLABORATION_BACKEND_BASE_URL: https://${DOMAIN}
COLLABORATION_SERVER_ORIGIN: https://${DOMAIN}
Y_PROVIDER_API_KEY_FILE: /run/secrets/y_api_key
YHUB_JWT_PRIVATE_KEY_FILE: /run/secrets/yhub_jwt_pk
YHUB_JWT_PRIVATE_KEY_FILE: /keys/yhub-jwt.pem
# Seed documents from the pre-v6 media bucket the first time they are opened.
# Only turn off once `abra app cmd <app> backend migrate_documents` covered all documents.
SOFT_MIGRATION: "${SOFT_MIGRATION:-true}"
@@ -120,14 +120,14 @@ x-minio-env: &minio-env
services:
app:
image: lasuite/impress-frontend:v6.0.3
image: lasuite/impress-frontend:v6.0.4
networks:
- backend
deploy:
labels:
- "traefik.enable=false"
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-120}"
- "coop-cloud.${STACK_NAME}.version=1.0.0+v6.0.3"
- "coop-cloud.${STACK_NAME}.version=1.0.1+v6.0.4"
user: "${DOCKER_USER:-1000}"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
@@ -137,7 +137,7 @@ services:
start_period: 10s
backend:
image: lasuite/impress-backend:v6.0.3
image: lasuite/impress-backend:v6.0.4
networks:
- backend
environment:
@@ -152,7 +152,9 @@ services:
user: "${DOCKER_USER:-1000}"
command: ["gunicorn", "-c", "/usr/local/etc/gunicorn/impress.py", "impress.wsgi:application"]
entrypoint: >
sh -c "if [ \"$$AUTO_MIGRATIONS\" = \"true\" ]; then /migrate.sh; fi && exec /abra-entrypoint.sh /usr/local/bin/entrypoint \"$$@\"" --
sh -c "while [ ! -s /keys/jwt.pem ]; do sleep 1; done; if [ \"$$AUTO_MIGRATIONS\" = \"true\" ]; then /migrate.sh; fi && exec /abra-entrypoint.sh /usr/local/bin/entrypoint \"$$@\"" --
volumes:
- jwt_keys:/keys:ro
configs:
- source: abra_entrypoint
target: /abra-entrypoint.sh
@@ -169,10 +171,9 @@ services:
- postgres_p
- y_api_key
- email_pass
- jwt_pk
celery:
image: lasuite/impress-backend:v6.0.3
image: lasuite/impress-backend:v6.0.4
networks:
- backend
healthcheck:
@@ -185,7 +186,10 @@ services:
command: ["celery", "-A", "impress.celery_app", "worker", "-l", "INFO"]
environment:
<<: [*common-env, *postgres-env, *yprovider-env]
entrypoint: ["/abra-entrypoint.sh", "/usr/local/bin/entrypoint"]
entrypoint: >
sh -c "while [ ! -s /keys/jwt.pem ]; do sleep 1; done; exec /abra-entrypoint.sh /usr/local/bin/entrypoint \"$$@\"" --
volumes:
- jwt_keys:/keys:ro
configs:
- source: abra_entrypoint
target: /abra-entrypoint.sh
@@ -199,11 +203,10 @@ services:
- postgres_p
- y_api_key
- email_pass
- jwt_pk
# Collaboration server: serves the websocket and holds the document content
yhub:
image: lasuite/impress-yhub:v6.0.3
image: lasuite/impress-yhub:v6.0.4
networks:
- backend
environment: *yhub-env
@@ -216,18 +219,19 @@ services:
start_period: 30s
# The server never creates its schema: run the idempotent init-db before every start
entrypoint: >
sh -c "export POSTGRES=\"postgres://docs:$$(node -e 'process.stdout.write(encodeURIComponent(require(\"fs\").readFileSync(\"/run/secrets/postgres_p\",\"utf8\").trim()))')@db:5432/yhub\" && node node_modules/@y/hub/bin/init-db.js && exec /usr/local/bin/entrypoint \"$$@\"" --
sh -c "while [ ! -s /keys/yhub-jwt.pem ]; do sleep 1; done; export POSTGRES=\"postgres://docs:$$(node -e 'process.stdout.write(encodeURIComponent(require(\"fs\").readFileSync(\"/run/secrets/postgres_p\",\"utf8\").trim()))')@db:5432/yhub\" && node node_modules/@y/hub/bin/init-db.js && exec /usr/local/bin/entrypoint \"$$@\"" --
command: ["node", "--import", "./dist/sentry.js", "dist/server.js"]
volumes:
- jwt_keys:/keys:ro
secrets:
- postgres_p
- y_api_key
- yhub_jwt_pk
- minio_ru
- minio_rp
# Valkey of yhub: holds updates not yet persisted to postgres, so it is a store, not a cache
yhub-valkey:
image: valkey/valkey:8.1.10-alpine
image: valkey/valkey:8.1.11-alpine
command: ["valkey-server", "--maxmemory-policy", "volatile-lru", "--appendonly", "yes", "--appendfsync", "everysec"]
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
@@ -242,9 +246,42 @@ services:
labels:
backupbot.backup: "${ENABLE_BACKUPS:-true}"
# Generates the two RSA keys the backend and yhub sign with, into a shared volume.
# They cannot be abra-generated secrets (PEM format) and Swarm secrets cannot be
# created at deploy time, so this idempotent sidecar creates them once and keeps them
# on the volume across redeploys. Both consumers wait for their file before starting.
jwt-keys:
image: lasuite/impress-yhub:v6.0.4
networks:
- backend
user: "0"
volumes:
- jwt_keys:/keys
healthcheck:
test: ["CMD-SHELL", "[ -s /keys/jwt.pem ] && [ -s /keys/yhub-jwt.pem ]"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
entrypoint: ["/bin/sh", "-c"]
command:
- |
set -eu
generate() {
target="/keys/$$1"
if [ ! -s "$$target" ]; then
node -e 'const fs=require("fs");const {generateKeyPairSync}=require("crypto");const {privateKey}=generateKeyPairSync("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}});fs.writeFileSync(process.argv[1],privateKey,{mode:0o400});' "$$target"
fi
}
generate jwt.pem
generate yhub-jwt.pem
chown -R "${DOCKER_USER:-1000}:${DOCKER_USER:-1000}" /keys
chmod 0400 /keys/jwt.pem /keys/yhub-jwt.pem
while true; do sleep 3600; done
# Conversion service only since v6 (no longer serves the collaboration)
y-provider:
image: lasuite/impress-y-provider:v6.0.3
image: lasuite/impress-y-provider:v6.0.4
networks:
- backend
healthcheck:
@@ -263,12 +300,12 @@ services:
- y_api_key
docspec:
image: ghcr.io/docspecio/api:3.0.2
image: ghcr.io/docspec/api:1.21.4
networks:
- backend
healthcheck:
# Use 127.0.0.1, which is required instead of localhost for this healtcheck because of elixir/busybox bindings
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:4000/health"]
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:3000/health"]
interval: 15s
timeout: 5s
retries: 3
@@ -302,7 +339,7 @@ services:
- postgres_p
redis:
image: redis:8.10.2
image: redis:8.10.3
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 15s
@@ -380,6 +417,7 @@ volumes:
postgres:
minio:
yhub_valkey:
jwt_keys:
configs:
nginx_conf:
@@ -412,12 +450,6 @@ secrets:
postgres_p:
external: true
name: ${STACK_NAME}_postgres_p_${SECRET_POSTGRES_P_VERSION}
jwt_pk:
external: true
name: ${STACK_NAME}_jwt_pk_${SECRET_JWT_PK_VERSION}
yhub_jwt_pk:
external: true
name: ${STACK_NAME}_yhub_jwt_pk_${SECRET_YHUB_JWT_PK_VERSION}
minio_rp:
external: true
name: ${STACK_NAME}_minio_rp_${SECRET_MINIO_RP_VERSION}
+13
View File
@@ -0,0 +1,13 @@
⚠️ Major upgrade to Docs v6: the collaboration server is replaced by the new `yhub`
service, and existing documents have to be migrated to it, or they open EMPTY.
`SECRET_COLLAB_SS_VERSION` and the `collab_ss` secret are no longer used. The two
RSA keys the backend and yhub sign with are generated automatically on first
deploy into the `jwt_keys` volume (the `jwt-keys` service) and reused afterwards;
no manual secret insertion is needed.
After deploying (SOFT_MIGRATION is on by default), migrate all documents:
abra app cmd <app-name> backend migrate_documents
Only then may you set SOFT_MIGRATION=false. See the README for details.