CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

fix(deploy): the caddy override belonged under services, not networks #5567

MergedXSccantynz wants to mergefix/override-caddy-under-servicesmainopened 2d ago
2 changed files+55−7
Modifiedscripts/docker-compose.coolify-override.yml+10−4View fileUnifiedSplit
1414 - default
1515 - coolify
1616
17networks:
18 coolify:
19 external: true
20
2117 # Caddy cannot run here. It binds host :80/:443, and on this box Coolify's
2218 # Traefik ("coolify-proxy") already owns both — so every `compose up` left a
2319 # caddy container stuck in `Created` and returned non-zero. auto-update.sh
3127 # a default service and still comes up with automatic Let's Encrypt certs.
3228 # Dies with Phase 2 alongside the rest of this override: when Coolify is
3329 # evicted, auto-update.sh stops including this file and caddy takes the edge.
30 #
31 # KEEP THIS UNDER `services:`. It was first appended to the end of the file,
32 # below `networks:`, where compose read it as a NETWORK named caddy carrying
33 # a `profiles` key — an invalid file, so every deploy died in about a second
34 # with "BUILD FAILED" and main became undeployable (2026-08-29). Indentation
35 # alone does not say which section a key belongs to.
3436 caddy:
3537 profiles:
3638 - dedicated-edge
39
40networks:
41 coolify:
42 external: true
Modifiedsrc/__tests__/auto-update-deploy.test.ts+45−3View fileUnifiedSplit
416416 // indistinguishable from a new one, which is the whole trap.
417417 const OVERRIDE = resolve("scripts/docker-compose.coolify-override.yml");
418418
419 test("caddy is behind a profile nothing activates", async () => {
419 /**
420 * Split the override into its top-level sections, so an assertion can say
421 * WHICH section a key lives in.
422 *
423 * The first version of this guard asserted /^\s{2}caddy:/m — text at
424 * two-space indent, anywhere in the file. The caddy block had been appended
425 * to the END, below `networks:`, so compose read it as a NETWORK named caddy
426 * carrying a `profiles` key. The file was invalid, every deploy died in
427 * about a second with "BUILD FAILED", main was undeployable for 20 minutes —
428 * and this test stayed green, because the string it looked for was present.
429 * Indentation does not tell you the parent.
430 */
431 async function sections(): Promise<Record<string, string>> {
420432 const yaml = await Bun.file(OVERRIDE).text();
421 expect(yaml).toMatch(/^\s{2}caddy:/m);
422 expect(yaml).toMatch(/profiles:\s*\n\s*-\s*dedicated-edge/);
433 const out: Record<string, string> = {};
434 let current = "";
435 for (const line of yaml.split(/\r?\n/)) {
436 const top = /^([a-z][a-z0-9_-]*):\s*$/.exec(line);
437 if (top) {
438 current = top[1]!;
439 out[current] = "";
440 } else if (current) {
441 out[current] += line + "\n";
442 }
443 }
444 return out;
445 }
446
447 test("caddy is behind a profile nothing activates — under services", async () => {
448 const s = await sections();
449 expect(Object.keys(s)).toContain("services");
450 // The whole point: caddy must be a SERVICE, not a network.
451 expect(s.services).toMatch(/^\s{2}caddy:/m);
452 expect(s.networks ?? "").not.toMatch(/^\s{2}caddy:/m);
453 expect(s.services).toMatch(/caddy:\s*\n\s*profiles:\s*\n\s*-\s*dedicated-edge/);
423454 // Nothing may turn it on: no --profile flag anywhere in the deploy path.
424455 const script = await Bun.file(SCRIPT).text();
425456 expect(script).not.toMatch(/--profile/);
426457 });
427458
459 test("the networks section declares only the external coolify network", async () => {
460 // A stray service key landing in here is exactly how this broke, so pin
461 // the section's whole contents rather than only what should be present.
462 const s = await sections();
463 const keys = (s.networks ?? "")
464 .split(/\r?\n/)
465 .map((l) => /^\s{2}([a-z][a-z0-9_-]*):/.exec(l)?.[1])
466 .filter((k): k is string => Boolean(k));
467 expect(keys).toEqual(["coolify"]);
468 });
469
428470 test("the override still declares the ingress network it exists for", async () => {
429471 // The profile addition must not disturb the reason this file exists:
430472 // attaching gluecron to `coolify` at CREATE time. Losing that silently
431473
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts