Skip to content

Commit a07062d

Browse files
brian-mannjennifer-shehaneryanthemanuel
authored
fix(dns-cache): prevent local family cache collisions (#32403)
* bump node types * add network tests to terminals * dont use the web-config, just use regular TS so that it compiles much faster and line numbers work * fix missing promise * cache families to include host + port; fix types * fix incorrect cacheKey * fix skipped tests and updated error messages likely due to node upgrade * cleanup a ton of test context * Add changelog entry * close servers after each test * Update packages/network/lib/agent.ts Co-authored-by: Ryan Manuel <ryanm@cypress.io> * update tests to pass inside + outside of docker * try this in docker * try to enable ipv6 in circleci docker config * escape * dont run this test in CI * revert * skip the other test * maybe this works * try this * Update .circleci/workflows.yml * oops * i do not think we need sudo * test * test * try machine * refactor * that was weird * that was weird * mess with daemon and sudo * escape < * modify /etc/hosts * Update .circleci/workflows.yml * Update .circleci/workflows.yml * Update .circleci/workflows.yml * remove dead code * Update branch condition in CircleCI workflow * Update .circleci/workflows.yml * clean up * clean up * fix cy in cy tests * fix cy in cy * Update packages/server/lib/server-base.ts --------- Co-authored-by: Jennifer Shehane <shehane.jennifer@gmail.com> Co-authored-by: Ryan Manuel <ryanm@cypress.io>
1 parent 9ebddda commit a07062d

File tree

10 files changed

+353
-147
lines changed

10 files changed

+353
-147
lines changed

.circleci/workflows.yml

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ executors:
147147
PLATFORM: linux
148148
# TODO: Disabling snapshots for now on Linux Arm 64 architectures. Will revisit with https://github.com/cypress-io/cypress/issues/23557
149149
DISABLE_SNAPSHOT_REQUIRE: 1
150+
linux-x64: &linux-x64-executor
151+
machine:
152+
image: ubuntu-2004:2024.11.1
153+
resource_class: medium
154+
environment:
155+
PLATFORM: linux
150156

151157
commands:
152158
# This command inserts SHOULD_PERSIST_ARTIFACTS into BASH_ENV. This way, we can define the variable in one place and use it in multiple steps.
@@ -1791,11 +1797,36 @@ jobs:
17911797
condition:
17921798
equal: [ *windows-executor, << parameters.executor >> ]
17931799
steps:
1794-
- run: yarn test-scripts
1795-
# run unit tests from each individual package
1796-
- run: yarn test
1797-
# run type checking for each individual package
1798-
- run: yarn lerna run types
1800+
- run:
1801+
name: Enable IPv6 in Docker
1802+
command: |
1803+
cat \<<'EOF' | sudo tee /etc/docker/daemon.json
1804+
{
1805+
"ipv6": true,
1806+
"fixed-cidr-v6": "2001:db8:1::/64"
1807+
}
1808+
EOF
1809+
cat \<<'EOF' | sudo tee /etc/hosts
1810+
127.0.0.1 localhost
1811+
::1 localhost
1812+
EOF
1813+
sudo service docker restart
1814+
- run:
1815+
name: Test scripts
1816+
command: |
1817+
source ./scripts/ensure-node.sh
1818+
yarn test-scripts
1819+
- run:
1820+
name: Test each individual package
1821+
command: |
1822+
source ./scripts/ensure-node.sh
1823+
# this is needed since we are have to be running as root to test some packages
1824+
sudo -E env "PATH=$PATH" yarn test
1825+
- run:
1826+
name: Test types
1827+
command: |
1828+
source ./scripts/ensure-node.sh
1829+
yarn lerna run types
17991830
- sanitize-verify-and-store-mocha-results:
18001831
expectedResultCount: 20
18011832

@@ -2908,6 +2939,7 @@ linux-x64-workflow: &linux-x64-workflow
29082939
requires:
29092940
- build
29102941
- unit-tests:
2942+
executor: linux-x64
29112943
requires:
29122944
- build
29132945
- verify-release-readiness:

.vscode/terminals.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@
8989
"onlySingle": true,
9090
"cwd": "[cwd]/packages/driver",
9191
"command": "yarn cypress:open"
92+
},
93+
{
94+
"name": "packages/network test",
95+
"focus": true,
96+
"onlySingle": true,
97+
"cwd": "[cwd]/packages/network",
98+
"command": "yarn test-watch [file]"
9299
}
93100
]
94101
}

cli/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
22
## 15.1.1
33

4-
_Released 09/16/2025 (PENDING)_
4+
_Released 9/9/2025 (PENDING)_
5+
6+
**Bugfixes:**
7+
8+
- We now properly partition the `host` with `port` when caching family DNS lookups. This resolves issues where some `localhost` URLs were not resolving in `cy.visit()` in Cypress when they should have. Fixes [#25397](https://github.com/cypress-io/cypress/issues/25397). Addressed in [#32403](https://github.com/cypress-io/cypress/pull/32403).
59

610
**Features:**
711

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
"@types/lodash": "^4.14.168",
114114
"@types/markdown-it": "12.2.3",
115115
"@types/mocha": "8.0.3",
116-
"@types/node": "20.16.0",
116+
"@types/node": "22.15.1",
117117
"@types/prismjs": "1.16.0",
118118
"@types/react": "18.3.12",
119119
"@types/react-dom": "18.3.1",

packages/network/.mocharc.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module.exports = {
33
'test/unit/**/*.ts',
44
'test/integration/**/*.ts'
55
],
6-
require: '../web-config/node-register',
6+
require: '@packages/ts/register',
77
timeout: 10000,
88
recursive: true
9-
}
9+
}

packages/network/lib/agent.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,17 @@ export const regenerateRequestHead = (req: http.ClientRequest) => {
148148
}
149149
}
150150

151-
const getFirstWorkingFamily = (
152-
{ port, host }: http.RequestOptions,
151+
export const getFirstWorkingFamily = (
152+
{ port, host }: Pick<http.RequestOptions, 'port' | 'host'>,
153153
familyCache: FamilyCache,
154-
cb: Function,
154+
cb: (family?: net.family) => void,
155155
) => {
156156
// this is a workaround for localhost (and potentially others) having invalid
157157
// A records but valid AAAA records. here, we just cache the family of the first
158158
// returned A/AAAA record for a host that we can establish a connection to.
159159
// https://github.com/cypress-io/cypress/issues/112
160160

161-
const isIP = net.isIP(host)
161+
const isIP = net.isIP(host) as net.family | 0
162162

163163
if (isIP) {
164164
// isIP conveniently returns the family of the address
@@ -170,13 +170,15 @@ const getFirstWorkingFamily = (
170170
return cb()
171171
}
172172

173-
if (familyCache[host]) {
174-
return cb(familyCache[host])
173+
const cacheKey = `${host}:${port}`
174+
175+
if (familyCache[cacheKey]) {
176+
return cb(familyCache[cacheKey])
175177
}
176178

177179
return getAddress(port, host)
178180
.then((firstWorkingAddress: net.Address) => {
179-
familyCache[host] = firstWorkingAddress.family
181+
familyCache[cacheKey] = firstWorkingAddress.family
180182

181183
return cb(firstWorkingAddress.family)
182184
})
@@ -246,7 +248,7 @@ export class CombinedAgent {
246248

247249
debug('addRequest called %o', { isHttps, ..._.pick(options, 'href') })
248250

249-
return getFirstWorkingFamily(options, this.familyCache, (family: net.family) => {
251+
return getFirstWorkingFamily(options, this.familyCache, (family?: net.family) => {
250252
options.family = family
251253

252254
debug('got family %o', _.pick(options, 'family', 'href'))

packages/network/test/integration/connect_spec.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ describe('lib/connect', function () {
1919
const server = net.createServer(_.partialRight(_.invoke, 'close'))
2020

2121
return Bluebird.fromCallback((cb) => {
22-
server.listen(0, '127.0.0.1', cb)
22+
server.listen({
23+
port: 0,
24+
host: '127.0.0.1',
25+
}, cb.bind(server))
2326
})
2427
.then(() => {
2528
return connect.getAddress(server.address().port, 'localhost')
@@ -31,19 +34,24 @@ describe('lib/connect', function () {
3134
})
3235
})
3336
.then(() => {
34-
server.close()
37+
return Bluebird.fromCallback((cb) => {
38+
server.close(cb)
39+
})
3540
})
3641
})
3742

3843
// Error: listen EADDRNOTAVAIL ::1
3944
// NOTE: add an ipv6 lo if to the docker container
40-
it.skip('resolves localhost on ::1 immediately', function () {
45+
it('resolves localhost on ::1 immediately', function () {
4146
this.timeout(50)
4247

4348
const server = net.createServer(_.partialRight(_.invoke, 'close'))
4449

4550
return Bluebird.fromCallback((cb) => {
46-
server.listen(0, '::1', cb)
51+
server.listen({
52+
port: 0,
53+
host: '::1',
54+
}, cb.bind(server))
4755
})
4856
.then(() => {
4957
return connect.getAddress(server.address().port, 'localhost')
@@ -55,7 +63,9 @@ describe('lib/connect', function () {
5563
})
5664
})
5765
.then(() => {
58-
server.close()
66+
return Bluebird.fromCallback((cb) => {
67+
server.close(cb)
68+
})
5969
})
6070
})
6171
})

0 commit comments

Comments
 (0)