feat(ci): run browser tests in docker run container on shared network #2

Closed
aureus wants to merge 4 commits from ci/browser-test-networking into main
Owner

The CI container is on the outer runner's bridge — its localhost cannot
reach tier containers port-mapped by the HOST daemon. The same DNAT
limitation that affected bootstrap also affects browser tests.

Fix: run the entire Playwright harness inside a transient container
on watchcraft-browser-ci (a pre-created HOST network). Tier Jellyfin
and Seerr containers join this network via a new CI overlay
(docker-compose.tier.ci.yml), so dev-server.ts can reach them by
container DNS name instead of localhost:PORT.

Key details:

  • -v $(pwd):/workspace -w /workspace: uses the bootstrap-proven
    mount pattern so artifacts written to /workspace persist to the
    CI workspace and are uploaded by the always-run artifact step.
  • HOST_WORKSPACE=$(pwd): injected so dev-server.ts builds HOST-
    accessible bind-mount paths for tier containers (the HOST daemon
    resolves sources against the HOST filesystem, not /workspace).
  • docker-compose.tier.ci.yml: adds DOTNET stability env vars to
    tier Jellyfin (same flags as the bootstrap overlay) and joins
    both services to watchcraft-browser-ci.
  • Playwright artifacts uploaded if: always() so the HTML report
    and screenshots are available on every CI run.
The CI container is on the outer runner's bridge — its localhost cannot reach tier containers port-mapped by the HOST daemon. The same DNAT limitation that affected bootstrap also affects browser tests. Fix: run the entire Playwright harness inside a transient container on watchcraft-browser-ci (a pre-created HOST network). Tier Jellyfin and Seerr containers join this network via a new CI overlay (docker-compose.tier.ci.yml), so dev-server.ts can reach them by container DNS name instead of localhost:PORT. Key details: - -v $(pwd):/workspace -w /workspace: uses the bootstrap-proven mount pattern so artifacts written to /workspace persist to the CI workspace and are uploaded by the always-run artifact step. - HOST_WORKSPACE=$(pwd): injected so dev-server.ts builds HOST- accessible bind-mount paths for tier containers (the HOST daemon resolves sources against the HOST filesystem, not /workspace). - docker-compose.tier.ci.yml: adds DOTNET stability env vars to tier Jellyfin (same flags as the bootstrap overlay) and joins both services to watchcraft-browser-ci. - Playwright artifacts uploaded if: always() so the HTML report and screenshots are available on every CI run.
feat(ci): run browser tests in docker run container on shared network
Some checks failed
PR Checks / test (pull_request) Failing after 5m22s
97dd9b7a52
The CI container is on the outer runner's bridge — its localhost cannot
reach tier containers port-mapped by the HOST daemon. The same DNAT
limitation that affected bootstrap also affects browser tests.

Fix: run the entire Playwright harness inside a transient container
on watchcraft-browser-ci (a pre-created HOST network). Tier Jellyfin
and Seerr containers join this network via a new CI overlay
(docker-compose.tier.ci.yml), so dev-server.ts can reach them by
container DNS name instead of localhost:PORT.

Key details:
- -v $(pwd):/workspace -w /workspace: uses the bootstrap-proven
  mount pattern so artifacts written to /workspace persist to the
  CI workspace and are uploaded by the always-run artifact step.
- HOST_WORKSPACE=$(pwd): injected so dev-server.ts builds HOST-
  accessible bind-mount paths for tier containers (the HOST daemon
  resolves sources against the HOST filesystem, not /workspace).
- docker-compose.tier.ci.yml: adds DOTNET stability env vars to
  tier Jellyfin (same flags as the bootstrap overlay) and joins
  both services to watchcraft-browser-ci.
- Playwright artifacts uploaded if: always() so the HTML report
  and screenshots are available on every CI run.
fix(ci): use login shell and run Seerr as root in CI containers
Some checks failed
PR Checks / test (pull_request) Failing after 5m37s
f362cf4bab
Two failures from the previous CI run:

1. tsx not found in transient docker run containers: the CI image
   initialises Node via a login-shell profile. sh -c does not source it,
   so tsx is not on PATH. Switching to bash -lc fixes both the bootstrap
   and browser test docker run invocations.

2. Seerr EACCES (mkdir /app/config/logs/): Seerr's image runs as a
   non-root UID and cannot write to its bind-mounted config dir in CI.
   Adding user: root to both CI overlays (bootstrap stack and tier
   stacks) resolves the permission error without affecting local dev.
fix(ci): run bootstrap and browser tests directly in job container
Some checks failed
PR Checks / test (pull_request) Failing after 5m34s
d4739ef052
node_modules lives in the job container's overlay filesystem. Transient
docker run containers launched against the HOST daemon bind-mount from
the HOST path, which does not include node_modules — causing tsx not found.

For bootstrap: connect the job container to the dev_default network with
docker network connect $(hostname), run tsx scripts directly in the job
container, then disconnect. Jellyfin and Seerr DNS names resolve immediately
after the network connect.

For browser tests: same pattern with the browser CI network. The Playwright
harness, tier lifecycle commands (docker compose), and spawned watchcraft
processes all run directly in the job container, which is connected to the
browser CI network so tier container DNS names resolve.

HOST_WORKSPACE is still passed so dev-server.ts can construct valid
bind-mount source paths for tier containers started via the HOST daemon.
fix(ci): use cgroup to find container ID for network connect
Some checks failed
PR Checks / test (pull_request) Failing after 5m27s
e434cae838
$(hostname) returns the container's hostname, not its container ID as
known to the Docker daemon. The runner sets a custom hostname that does
not match the Docker container ID, causing 'No such container' errors.

Extract the real 64-char container ID from /proc/self/cgroup (reliable
on both cgroup v1 and v2) and pass it to docker network connect/disconnect.

Also dump /proc/self/cgroup in the diagnostics step so the extracted ID
is visible in future failure logs.
aureus closed this pull request 2026-05-25 14:31:01 +00:00
Some checks failed
PR Checks / test (pull_request) Failing after 5m27s

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aureus/watchcraft!2
No description provided.