diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index babb535..4e75f92 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,24 +6,137 @@ on: pull_request: jobs: - setup-docker: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [macos-15-intel] - name: A job to perform a self-test on this Github Action + test-localhost: + runs-on: macos-15-intel + name: "Test localhost access (macos-15)" steps: - # To use this repository's private action, - # you must check out the repository - name: Checkout uses: actions/checkout@v5 - - name: Setup Docker on macOS using Colima, Lima-VM, and Homebrew. - uses: ./ # Uses an action in the root directory + - name: Setup Docker on macOS id: docker - - name: Get the Docker client version + uses: ./ + with: + colima-network-address: false + - name: Log Colima info + run: | + colima status + colima list + - name: Run nginx and test localhost access + run: | + docker run --rm -d -p 8080:80 --name test-nginx \ + --health-cmd "curl --fail http://localhost || exit 1" \ + --health-interval 2s --health-retries 15 --health-start-period 5s --health-timeout 2s \ + nginx:latest + + for attempt in {1..10}; do + STATUS=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}starting{{end}}' test-nginx) + if [ "$STATUS" = "healthy" ]; then + break + fi + if [ "$STATUS" = "unhealthy" ]; then + echo "nginx container reported unhealthy" >&2 + docker logs test-nginx + exit 1 + fi + sleep 1 + done + + if [ "$STATUS" != "healthy" ]; then + echo "nginx container never became healthy" >&2 + docker logs test-nginx + exit 1 + fi + + echo "Testing curl via localhost:8080" + if ! curl -s -o /dev/null -w "%{http_code}" http://localhost:8080 | grep -q "200"; then + echo "Failed to curl using localhost:8080" + docker logs test-nginx + docker stop test-nginx + exit 1 + fi + echo "Successfully connected via localhost:8080" + + docker stop test-nginx + - name: Log versions run: | echo "Docker client version: ${{ steps.docker.outputs.docker-client-version }}" - - name: Get the Colima version + echo "Colima version: ${{ steps.docker.outputs.colima-version }}" + + test-network-address: + runs-on: macos-15-intel + name: "Test VM network address with sudo curl (macos-15)" + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Setup Docker on macOS (with network-address) + id: docker + uses: ./ + with: + colima-network-address: true + - name: Get Colima IP addresses run: | + COLIMA_IP=$(colima list | grep -E "^\s*default\s+" | awk '{print $NF}') + COLIMA_GATEWAY_IP=$(colima ssh -- ip route | grep 'default via' | grep 'dev col0' | awk '{print $3}') + echo "Colima IP address: $COLIMA_IP" + echo "Colima Gateway IP address: $COLIMA_GATEWAY_IP" + echo "COLIMA_IP=$COLIMA_IP" >> $GITHUB_ENV + echo "COLIMA_GATEWAY_IP=$COLIMA_GATEWAY_IP" >> $GITHUB_ENV + - name: Log Colima info + run: | + colima status + colima list + colima ssh -- ip route + - name: Run nginx and test VM network address access with sudo curl + run: | + docker run --rm -d -p 8080:80 --name test-nginx \ + --health-cmd "curl --fail http://localhost || exit 1" \ + --health-interval 2s --health-retries 15 --health-start-period 5s --health-timeout 2s \ + nginx:latest + + for attempt in {1..10}; do + STATUS=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}starting{{end}}' test-nginx) + if [ "$STATUS" = "healthy" ]; then + break + fi + if [ "$STATUS" = "unhealthy" ]; then + echo "nginx container reported unhealthy" >&2 + docker logs test-nginx + exit 1 + fi + sleep 1 + done + + if [ "$STATUS" != "healthy" ]; then + echo "nginx container never became healthy" >&2 + docker logs test-nginx + exit 1 + fi + + FAILED=0 + + echo "Testing sudo curl with Colima VM IP: $COLIMA_IP:8080" + if ! sudo curl -s -o /dev/null -w "%{http_code}" "http://$COLIMA_IP:8080" | grep -q "200"; then + echo "Failed to curl using Colima IP: $COLIMA_IP" + FAILED=1 + else + echo "Successfully connected to Colima VM IP: $COLIMA_IP" + fi + + echo "Testing sudo curl with Colima Gateway IP: $COLIMA_GATEWAY_IP:8080" + if ! sudo curl -s -o /dev/null -w "%{http_code}" "http://$COLIMA_GATEWAY_IP:8080" | grep -q "200"; then + echo "Failed to curl using Colima Gateway IP: $COLIMA_GATEWAY_IP" + FAILED=1 + else + echo "Successfully connected to Colima Gateway IP: $COLIMA_GATEWAY_IP" + fi + + docker stop test-nginx + + if [ $FAILED -ne 0 ]; then + echo "One or more curl tests failed" >&2 + exit 1 + fi + - name: Log versions + run: | + echo "Docker client version: ${{ steps.docker.outputs.docker-client-version }}" echo "Colima version: ${{ steps.docker.outputs.colima-version }}" diff --git a/.gitignore b/.gitignore index e7171c8..db033f4 100644 --- a/.gitignore +++ b/.gitignore @@ -124,3 +124,4 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* +.DS_Store diff --git a/README.md b/README.md index 253cfa8..efae7e4 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ I intend this action to be kept as simple as possible: - `macos-15-large` - `macos-15-intel` -## `arm64` processors (M-series) used on `macos-14` images and beyond are unsupported +## `arm64` processors (M-series) used on `macos-15` images and beyond are unsupported > [!WARNING] > Apple added support for nested virtualization starting on M3 processors @@ -99,3 +99,69 @@ The version of Docker Compose that was installed. echo "Docker client version: ${{ steps.setup-docker.outputs.docker-client-version }}" echo "Docker compose version: ${{ steps.setup-docker.outputs.docker-compose-version }}" ``` + +## Known Issues + +### macOS 15+ Network Address Unreachable + +> [!WARNING] +> On macOS 15 (Sequoia) and newer, the Colima VM's network address (e.g., `192.168.64.x`) +> is unreachable from regular user processes. This is due to Apple's **Local Network Privacy (LNP)** +> restrictions introduced in macOS 15. + +#### The Problem + +Apple's macOS 15 introduced Local Network Privacy policies that restrict applications from +accessing local network addresses without explicit permission. This affects: + +- Accessing services running in Docker containers via the Colima VM's IP address. +- UDP traffic (required for QUIC/HTTP3) — `localhost` port forwarding only supports TCP. +- Any workflow that relies on direct network communication with the VM through the Colima VM IP. + +This is **not a bug in this action, Colima, or Lima** — it's a platform-level restriction +from Apple that currently has no complete workaround. + +#### Upstream Tracking + +- **GitHub Actions issue**: [actions/runner-images#10924](https://github.com/actions/runner-images/issues/10924) +- **This action's issue**: [#56](https://github.com/douglascamata/setup-docker-macos-action/issues/56) +- **Colima issue**: [abiosoft/colima#1448](https://github.com/abiosoft/colima/issues/1448) + +GitHub has filed feedback with Apple (`FB16213134`) but there is currently no resolution. +We are blocked by both GitHub Actions and Apple on a proper fix. + +#### Workarounds + +| Workaround | Pros | Cons | +|------------|------|------| +| **Use `localhost` port forwarding** | Works for TCP, no special setup | No UDP support (breaks QUIC/HTTP3) | +| Run clients as `root` user | Bypasses LNP for VM IP access | Requires elevated privileges for network access | + +##### Using `root` for VM network access + +Root processes are exempt from Apple's LNP restrictions. If you need to access the Colima +VM's network address directly, run your network client as `root` or with `sudo`: + +```yml +- name: Setup Docker with network address + uses: douglascamata/setup-docker-macos-action@v1 + with: + colima-network-address: true + +- name: Get Colima VM IP + run: | + COLIMA_IP=$(colima list | awk '/default/ {print $NF}') + echo "COLIMA_IP=$COLIMA_IP" >> $GITHUB_ENV + +- name: Access service via VM IP (requires sudo) + run: | + # Regular curl will fail due to LNP restrictions + # curl http://$COLIMA_IP:8080 # ❌ Blocked by macOS 15 LNP + + # Use sudo to bypass LNP restrictions + sudo curl http://$COLIMA_IP:8080 # ✅ Works +``` + +> [!NOTE] +> Running Colima itself as root (`sudo colima start`) is **not supported** by Lima/Colima +> and will cause issues. Only run the network client (curl, wget, etc.) as root.