This commit is contained in:
+10
-3
@@ -92,14 +92,21 @@ describe("n8n-sandbox post-install documentation", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("modern compose files preserve runtime semantics", () => {
|
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')
|
const fileContent = await getFile('n8n-sandbox', 'docker-compose.yml')
|
||||||
expect(fileContent).not.toBeNull()
|
expect(fileContent).not.toBeNull()
|
||||||
|
|
||||||
const parsed = YAML.parse(fileContent || '')
|
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['x-runtipi']?.schema_version).toBe(2)
|
||||||
expect(parsed.services?.['sandbox-certs']?.restart).toBe('no')
|
expect(certs?.restart).toBe('unless-stopped')
|
||||||
expect(parsed.services?.['sandbox-api']?.['x-runtipi']?.is_main).toBe(true)
|
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']?.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')
|
expect(parsed.services?.['sandbox-runner-1']?.healthcheck?.test).toContain('https://localhost:8080/readyz')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"no_gui": true,
|
"no_gui": true,
|
||||||
"dynamic_config": true,
|
"dynamic_config": true,
|
||||||
"port": 8080,
|
"port": 8080,
|
||||||
"tipi_version": 3,
|
"tipi_version": 4,
|
||||||
"min_tipi_version": "4.7.0",
|
"min_tipi_version": "4.7.0",
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"author": "n8n",
|
"author": "n8n",
|
||||||
|
|||||||
@@ -32,24 +32,31 @@
|
|||||||
services:
|
services:
|
||||||
sandbox-certs:
|
sandbox-certs:
|
||||||
image: n8nio/n8n-sandbox-service-api:1.3.0
|
image: n8nio/n8n-sandbox-service-api:1.3.0
|
||||||
# Obligatoire sous Runtipi : sans cette ligne le builder injecte
|
# Runtipi considere l'app arretee si un seul de ses conteneurs est sorti.
|
||||||
# restart: unless-stopped et ce job one-shot boucle en redemarrage.
|
# Le bootstrap reste donc actif et sain apres la generation idempotente.
|
||||||
restart: "no"
|
restart: unless-stopped
|
||||||
user: "0:0"
|
user: "0:0"
|
||||||
entrypoint: ["sh", "-c"]
|
entrypoint: ["sh", "-c"]
|
||||||
# Genere les certs (idempotent) puis fixe les droits pour l'utilisateur
|
# Genere les certs, fixe les droits pour sandbox-api, publie l'etat ready,
|
||||||
# sandbox-api de l'image : /tls/api et le repertoire SQLite de l'API
|
# puis reste actif sans ouvrir de port ni lancer de service reseau.
|
||||||
# (en bind mount, Docker cree le dossier en root sinon).
|
|
||||||
command:
|
command:
|
||||||
- >
|
- >
|
||||||
bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api
|
bootstrap-mtls.sh --out-dir /tls --api-san sandbox-api
|
||||||
--control-san-prefix sandbox-runner &&
|
--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:
|
environment:
|
||||||
NUM_RUNNERS: "1"
|
NUM_RUNNERS: "1"
|
||||||
volumes:
|
volumes:
|
||||||
- ${APP_DATA_DIR}/data/tls:/tls
|
- ${APP_DATA_DIR}/data/tls:/tls
|
||||||
- ${APP_DATA_DIR}/data/api:/var/lib/n8n-sandbox-api
|
- ${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:
|
sandbox-api:
|
||||||
image: n8nio/n8n-sandbox-service-api:1.3.0
|
image: n8nio/n8n-sandbox-service-api:1.3.0
|
||||||
@@ -57,7 +64,7 @@ services:
|
|||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
sandbox-certs:
|
sandbox-certs:
|
||||||
condition: service_completed_successfully
|
condition: service_healthy
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}"
|
SANDBOX_API_KEYS: "${SANDBOX_API_KEYS}"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Sandbox auto-hébergé pour l'**AI Assistant** de n8n (configuration « Self-hos
|
|||||||
|
|
||||||
| Service | Rôle |
|
| 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-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. |
|
| `sandbox-runner-1` | Docker-in-Docker **privileged** : crée et exécute les conteneurs sandbox. |
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user