From 0a5476793eb80cbdfd5ffaab5efef3606fec7672 Mon Sep 17 00:00:00 2001 From: git-hermes Date: Thu, 3 Sep 2026 10:28:42 +0200 Subject: [PATCH] fix(n8n-sandbox): keep Runtipi app status healthy --- __tests__/apps.test.ts | 13 ++++++++++--- apps/n8n-sandbox/config.json | 2 +- apps/n8n-sandbox/docker-compose.yml | 23 +++++++++++++++-------- apps/n8n-sandbox/metadata/description.md | 2 +- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/__tests__/apps.test.ts b/__tests__/apps.test.ts index 304ba65..5fa8519 100644 --- a/__tests__/apps.test.ts +++ b/__tests__/apps.test.ts @@ -92,14 +92,21 @@ describe("n8n-sandbox post-install documentation", () => { }) describe("modern compose files preserve runtime semantics", () => { - test("n8n-sandbox keeps its one-shot certificate service", async () => { + test("n8n-sandbox keeps its certificate bootstrap healthy for Runtipi", async () => { const fileContent = await getFile('n8n-sandbox', 'docker-compose.yml') expect(fileContent).not.toBeNull() const parsed = YAML.parse(fileContent || '') + const certs = parsed.services?.['sandbox-certs'] + const api = parsed.services?.['sandbox-api'] + expect(parsed['x-runtipi']?.schema_version).toBe(2) - expect(parsed.services?.['sandbox-certs']?.restart).toBe('no') - expect(parsed.services?.['sandbox-api']?.['x-runtipi']?.is_main).toBe(true) + expect(certs?.restart).toBe('unless-stopped') + expect(certs?.command?.join(' ')).toContain('touch /tmp/certs-ready') + expect(certs?.command?.join(' ')).toContain('tail -f /dev/null') + expect(certs?.healthcheck?.test).toContain('test -f /tmp/certs-ready') + expect(api?.depends_on?.['sandbox-certs']?.condition).toBe('service_healthy') + expect(api?.['x-runtipi']?.is_main).toBe(true) expect(parsed.services?.['sandbox-runner-1']?.environment?.SANDBOX_RUNNER_HTTP_BASE_URL).toBe('https://sandbox-runner-1:8080') expect(parsed.services?.['sandbox-runner-1']?.healthcheck?.test).toContain('https://localhost:8080/readyz') }) diff --git a/apps/n8n-sandbox/config.json b/apps/n8n-sandbox/config.json index 4899a59..93facc9 100644 --- a/apps/n8n-sandbox/config.json +++ b/apps/n8n-sandbox/config.json @@ -6,7 +6,7 @@ "no_gui": true, "dynamic_config": true, "port": 8080, - "tipi_version": 3, + "tipi_version": 4, "min_tipi_version": "4.7.0", "version": "1.3.0", "author": "n8n", diff --git a/apps/n8n-sandbox/docker-compose.yml b/apps/n8n-sandbox/docker-compose.yml index d5b58d6..efa1de3 100644 --- a/apps/n8n-sandbox/docker-compose.yml +++ b/apps/n8n-sandbox/docker-compose.yml @@ -32,24 +32,31 @@ services: sandbox-certs: image: n8nio/n8n-sandbox-service-api:1.3.0 - # Obligatoire sous Runtipi : sans cette ligne le builder injecte - # restart: unless-stopped et ce job one-shot boucle en redemarrage. - restart: "no" + # Runtipi considere l'app arretee si un seul de ses conteneurs est sorti. + # Le bootstrap reste donc actif et sain apres la generation idempotente. + restart: unless-stopped user: "0:0" entrypoint: ["sh", "-c"] - # Genere les certs (idempotent) puis fixe les droits pour l'utilisateur - # sandbox-api de l'image : /tls/api et le repertoire SQLite de l'API - # (en bind mount, Docker cree le dossier en root sinon). + # Genere les certs, fixe les droits pour sandbox-api, publie l'etat ready, + # puis reste actif sans ouvrir de port ni lancer de service reseau. command: - > bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api --control-san-prefix sandbox-runner && - chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api + chown -R sandbox-api:sandbox-api /tls/api /var/lib/n8n-sandbox-api && + touch /tmp/certs-ready && + exec tail -f /dev/null environment: NUM_RUNNERS: "1" volumes: - ${APP_DATA_DIR}/data/tls:/tls - ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api + healthcheck: + test: "test -f /tmp/certs-ready" + interval: 5s + timeout: 2s + retries: 12 + start_period: 5s sandbox-api: image: n8nio/n8n-sandbox-service-api:1.3.0 @@ -57,7 +64,7 @@ services: depends_on: sandbox-certs: - condition: service_completed_successfully + condition: service_healthy environment: SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}" diff --git a/apps/n8n-sandbox/metadata/description.md b/apps/n8n-sandbox/metadata/description.md index bc77bd2..bc8bca6 100644 --- a/apps/n8n-sandbox/metadata/description.md +++ b/apps/n8n-sandbox/metadata/description.md @@ -4,7 +4,7 @@ Sandbox auto-hébergé pour l'**AI Assistant** de n8n (configuration « Self-hos | Service | Rôle | |---|---| -| `sandbox-certs` | Job one-shot : génère la CA privée et les certificats mTLS, puis s'arrête. | +| `sandbox-certs` | Initialise la CA privée et les certificats mTLS, puis reste inactif et sain pour que Runtipi conserve l'app au statut « Démarré ». | | `sandbox-api` | Point d'entrée HTTP interne (`:8080`) que n8n appelle pour exécuter du code. | | `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |