fix(net): thread hops into session creation; disambiguate card tests — #2453
test-web / test (push) Successful in 42s
test-go / test (push) Failing after 43s
test-go / integration (push) Failing after 4m22s

Two CI failures from 381e9ced, both mine.

**Go (vet, which cascaded into the integration job).** Widening
auth.ClientIP to take a hop count, I updated the middleware that TOUCHES a
session but missed the two places that CREATE one — handleLogin and
handleRegister. So `created_ip`, the frozen origin address that the whole
"address changed" comparison rests on, was the one value still being
computed the old way. Both now read h.netSettings.Hops(), which is nil-safe
so test handlers constructed without the service still work.

Worth noting the shape of this miss: I checked call sites by searching for
the middleware's own usage and stopped there, rather than for every caller of
the function whose signature I changed. vet found it in seconds; a grep for
`auth.ClientIP(` would have too.

**Web (vitest).** Three tests waited on `findByText('198.51.100.7')`, which
matches TWO elements in the fixture — the detected client address and the
forwarded chain, identical strings for a single-proxy setup — and findByText
throws on multiple matches. Now they wait on the unique "Your address right
now" label and assert the address with getAllByText where duplication is
legitimate. The duplication is correct behaviour, so the test moved rather
than the component.
This commit is contained in:
2026-08-05 10:14:38 -04:00
parent 381e9cedb7
commit a07fb3867a
3 changed files with 8 additions and 5 deletions
+1 -1
View File
@@ -100,7 +100,7 @@ func (h *handlers) handleLogin(w http.ResponseWriter, r *http.Request) {
// the active-sessions surface: a session that was born somewhere the
// user recognises but is being used from somewhere they don't is the
// case this whole surface exists to surface.
Ip: auth.ClientIP(r),
Ip: auth.ClientIP(r, h.netSettings.Hops()),
}); err != nil {
h.logger.Error("api: insert session failed", "err", err)
writeErr(w, apierror.InternalMsg("insert failed", err))
+1 -1
View File
@@ -175,7 +175,7 @@ func (h *handlers) handleRegister(w http.ResponseWriter, r *http.Request) {
UserID: user.ID,
TokenHash: auth.HashSessionToken(sessionToken),
UserAgent: r.UserAgent(),
Ip: auth.ClientIP(r),
Ip: auth.ClientIP(r, h.netSettings.Hops()),
}); err != nil {
h.logger.Error("register: insert session failed", "err", err)
writeErr(w, apierror.Internal(err))
@@ -34,7 +34,10 @@ describe('NetworkSettingsCard', () => {
getNetworkSettings.mockResolvedValue(settings());
render(NetworkSettingsCard);
expect(await screen.findByText('198.51.100.7')).toBeTruthy();
// The address legitimately appears twice — as the detected client and
// inside the forwarded chain — so wait on the unique label, not the value.
await screen.findByText('Your address right now');
expect(screen.getAllByText('198.51.100.7').length).toBeGreaterThan(0);
expect(screen.getByText('172.18.0.1:40000')).toBeTruthy();
});
@@ -83,7 +86,7 @@ describe('NetworkSettingsCard', () => {
);
render(NetworkSettingsCard);
await screen.findByText('198.51.100.7');
await screen.findByText('Your address right now');
expect(screen.queryByText(/arrived with/)).toBeNull();
});
@@ -101,6 +104,6 @@ describe('NetworkSettingsCard', () => {
const retry = await screen.findByRole('button', { name: 'Try again' });
getNetworkSettings.mockResolvedValue(settings());
await fireEvent.click(retry);
await screen.findByText('198.51.100.7');
await screen.findByText('Your address right now');
});
});