Skip to content

Commit

Permalink
ci/cd: fix IPv6 requests not working with fetch
Browse files Browse the repository at this point in the history
This commit fixes:

- Docker build checks failing because `localhost` is resolving to IPv6.
- External URL checks failing because external URLs are resolving to IPv6.

This happens because GitHub runners do not support IPv6 but the fetch
API in Node tries to send IPv6 requests, failing with
`UND_ERR_CONNECT_TIMEOUT`.

This commit introduces a new action `force-ipv4` that disables IPv6
support on system level causing all requests to be IPv4, resolving
connectivity issues.

Node fetch requests failing with `UND_ERR_CONNECT_TIMEOUT` on GitHub
runners:

- actions/runner-images$9540
- actions/runner$3213

Details on lack of IPv6 support on GitHub runners:

- actions/runner$3138
- actions/runner-images$668

Missing Happy Eyeballs in `fetch` API:

- nodejs/undici$1531
- nodejs/node$41625
  • Loading branch information
undergroundwires committed Mar 28, 2024
1 parent 8a5592f commit 2b54f8e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .github/actions/force-ipv4/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
inputs:
project-root:
required: false
default: '.'
runs:
using: composite
steps:
-
name: Run prefer IPv4 script
shell: bash
run: ./.github/actions/force-ipv4/force-ipv4.sh
working-directory: ${{ inputs.project-root }}
50 changes: 50 additions & 0 deletions .github/actions/force-ipv4/force-ipv4.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash

main() {
if is_linux; then
echo 'Configuring Linux...'
disable_ipv6_on_linux
elif is_macos; then
echo 'Configuring macOS...'
disable_ipv6_on_macos
fi
}

is_linux() {
[[ "$(uname -s)" == "Linux" ]]
}

is_macos() {
[[ "$(uname -s)" == "Darwin" ]]
}

disable_ipv6_on_linux() {
# Temporarily and immediately disable IPv6
echo '1' | sudo tee /proc/sys/net/ipv6/conf/all/disable_ipv6 > /dev/null
echo '1' | sudo tee /proc/sys/net/ipv6/conf/default/disable_ipv6 > /dev/null
# Other approaches considered:
# - Prefer IPv4 in `/etc/gai.conf`: Requires proper configuration (just `precedence ::ffff:0:0/96 100`) is not enough.
# - Using `sysctl` command: Results in node to exit with code `13`.
# - Writing to `/etc/sysctl.conf`: Results in node to exit with code `13`.
}

prefer_ipv4_on_linux() {
local -r gai_conf="/etc/gai.conf"
if [ ! -f "$gai_conf" ]; then
echo "Creating $gai_conf since it doesn't exist..."
touch "$gai_conf"
fi
echo "precedence ::ffff:0:0/96 100" | sudo tee -a "$gai_conf" > /dev/null
echo "Configuration complete."
}

disable_ipv6_on_macos() {
networksetup -listallnetworkservices \
| tail -n +2 \
| while IFS= read -r interface; do
echo "Disabling IPv6 on: $interface"
networksetup -setv6off "$interface"
done
}

main
3 changes: 3 additions & 0 deletions .github/workflows/checks.build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ jobs:
-
name: Run Docker image on port 8080
run: docker run -d -p 8080:80 --rm --name privacy.sexy undergroundwires/privacy.sexy:latest
-
name: Prefer IPv4 # GitHub runners do not support IPv6 and requests fail when they try to connect to IPv6 addresses by default.
uses: ./.github/actions/force-ipv4
-
name: Check server is up and returns HTTP 200
run: >-
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/checks.external-urls.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
-
name: Install dependencies
uses: ./.github/actions/npm-install-dependencies
-
name: Force IPv4 # GitHub runners do not support IPv6 and requests fail when they try to connect to IPv6 addresses by default.
uses: ./.github/actions/force-ipv4
-
name: Test
run: npm run check:external-urls

0 comments on commit 2b54f8e

Please sign in to comment.