Skip to content

test(integration): TLS cert hot-reload multi-worker regression test (#586) - #1314

Merged
kriszyp merged 2 commits into
mainfrom
kris/586-cert-reload-test
Jun 18, 2026
Merged

kriszyp merged 2 commits into
mainfrom
kris/586-cert-reload-test

Conversation

@kriszyp

@kriszyp kriszyp commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds integrationTests/security/cert-reload.test.ts as a regression guard for TLS certificates not auto-reloaded on worker threads (flipping/stale cert after renewal) #586 (per-worker TLS context divergence on cert renewal)
  • Boots Harper with 2 HTTP workers (overrides the harness default of 1 via HARPER_SET_CONFIG threads.count)
  • Swaps the on-disk server cert (same key, new serial), polls until the swap is observed, waits a 2.5s settling period for all workers' independent 1.5s debounces to complete, then fires 40 parallel TLS handshakes via Promise.allSettled and asserts none serve the stale serial

How it catches the bug

The propagation path is: main-thread fs.watch → write to system.hdb_certificate → each worker's updateTLS() subscription callback. If the subscribe notification fails to reach a worker, roughly half of 40 SO_REUSEPORT-balanced connections would return the old serial and the test fails. With the fix in place (table-subscription design), all workers rebuild their SecureContext and every handshake serves the new serial.

Test plan

  • Passes 3/3 runs locally (~4s per run including settling sleep)
  • Gemini (agy) review — two findings applied: settling sleep after poll break, Promise.allSettled over Promise.all
  • Rejected false-positive finding: SNI servername=cert-reload-test.harper.local does match our cert specifically via secureContexts map (CN-keyed by createTLSSelector), not just the default context

Closes #586

🤖 Generated with Claude Code

…st (#586)

Adds integrationTests/security/cert-reload.test.ts which boots Harper
with >= 2 HTTP workers, swaps the on-disk server certificate, then
asserts that all 40 subsequent TLS handshakes (load-balanced by
SO_REUSEPORT across workers) serve the new serial number — catching any
per-worker divergence in the table-subscription propagation path.

Uses same private key / new serial to isolate cert propagation from
key-reload timing. Includes a 2.5s settling sleep after first-observed
reload to let all workers' independent 1.5s debounces complete before
the hammer assertions run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new integration test (cert-reload.test.ts) to verify that TLS certificate hot-reloads propagate correctly to all HTTP workers, preventing a regression where some workers continue serving stale certificates. The feedback recommends destroying the socket in the error event handler of the TLS connection to prevent potential resource leaks or hanging connections.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

socket.destroy();
reject(new Error('TLS connection timed out'));
});
socket.on('error', reject);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the general rules, when connecting to a TCP port, the socket must be destroyed in all event handlers (connect, timeout, error) to prevent resource leaks and hanging connections. Please ensure that socket.destroy() is called in the error event handler.

		socket.on('error', (err) => {
			socket.destroy();
			reject(err);
		});
References
  1. When using node:net to connect to a TCP port, set an explicit timeout on the socket and ensure that the socket is destroyed in all event handlers (connect, timeout, error) to prevent resource leaks and hanging connections.

@claude

claude Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

@kriszyp
kriszyp merged commit 66bae4a into main Jun 18, 2026
46 of 47 checks passed
@kriszyp
kriszyp deleted the kris/586-cert-reload-test branch June 18, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TLS certificates not auto-reloaded on worker threads (flipping/stale cert after renewal)

2 participants