# Hermetic e2e stand override for ../../deploy/docker-compose.yml (plan C.4). # # Applied as a second -f on top of the SHIPPED compose file, not a separate # test compose — the whole point is to exercise cap_drop/cap_add/ # no-new-privileges exactly as documented, not a laxer stand-in. Run only via # `make e2e`, which also sets --project-directory to a scratch stage # directory so the base file's relative ./data and ./certs bind mounts land # there instead of next to a real deployment, and -p selfpost-e2e so the # containers/network never collide with a prod stack on the same host. # # `ports:` and `networks:` use the compose-spec `!override` merge tag to fully # replace the base file's list rather than concatenate with it (the default # merge behaviour for sequences) — otherwise the real 465/587/8080 would stay # published here too and collide with a prod container on the same host. services: selfpost: # Crash-looping with unless-stopped makes `compose exec` fail with # "Container is restarting" and hides the entrypoint/supervisord exit # reason; keep the stand exited so logs stay attached to one attempt. restart: "no" build: # Resolved relative to --project-directory (.stage), NOT this file's own # directory — compose build.context paths follow the project directory, # unlike bind-mount volume paths, which is the same reason ./data and # ./certs above need no path here at all. context: ../../.. dockerfile: build/Dockerfile args: VERSION: e2e image: selfpost:e2e environment: SELFPOST_HOSTNAME: mail.e2e.test # Plain HTTP panel for the test client — no reverse proxy in this stand. PANEL_COOKIE_SECURE: "false" # The panel's deliverability checks query resolvers directly rather than # the container's own (see internal/dnscheck), so the fake zone has to be # named here too — `dns:` below only redirects the system resolver. SELFPOST_DNS_RESOLVERS: 10.77.0.10:53 # High enough that the whole suite's other ~10 sends (positive path, # level-2 test, the various rejected attempts) never trip it by # accident — only the dedicated level-1 test (negative check 4, which # loops well past this count) is meant to hit it. RATE_LIMIT_MESSAGES_PER_IP: "50" RATE_LIMIT_WINDOW_SECONDS: "60" ports: !override - "20465:465" - "20587:587" - "20025:25" - "127.0.0.1:20080:8080" dns: - 10.77.0.10 networks: !override e2e: depends_on: - coredns - sink # Fake authoritative DNS for e2e.test (plan C.4): serves the DKIM/host # records the test harness publishes, so Postfix's outbound MX lookup for # the sink and the panel's own dnscheck resolve inside the isolated network # instead of hitting the real internet. # # Pinned to a release tag rather than `latest`, so a CoreDNS upload cannot # change what the release gate runs against between two runs of the same # commit. Not a digest: the tag is a multi-arch manifest and the stand has to # come up on arm64 developer machines as well as amd64 CI. coredns: image: coredns/coredns:1.14.6 command: ["-conf", "/dns/Corefile"] volumes: - ./dns-stage:/dns networks: e2e: ipv4_address: 10.77.0.10 ports: - "20053:53/udp" # Sink-MX: accepts any inbound mail and dumps each transaction to its own # file under ./mail-stage, which the harness reads directly to check the # DKIM-Signature header Postfix/OpenDKIM produced. sink: build: context: ../sink volumes: - ./mail-stage:/mail networks: e2e: ipv4_address: 10.77.0.11 networks: e2e: ipam: config: - subnet: 10.77.0.0/24