test_tls_startup_failure_fallback_to_http read only the first 2000 bytes of
server stdout to assert 'TLS setup failed'. When the test interpreter lacks
optional deps (requests/websockets), startup emits a burst of plugin/tool
import warnings + the startup-config banner BEFORE the TLS line, pushing the
marker past the 2000-byte window -> spurious failure. Drain all
currently-available stdout (5s deadline, short-circuit on the marker) instead
of a single fixed-size read. Verified failing->passing in a fresh venv without
the optional deps. Test-only; distinct from the agent-package-isolation flake
cause already fixed in the same test.
* test(#4740): pin HERMES_HOME in readonly-scope pool test to fix order-dependent flake
test_active_request_readonly_scope_blocks_pool_env_seed failed only under
full-suite ordering (passed in isolation). Root cause, captured via an
assertion-time diagnostic: the readonly scope correctly blocks the process-env
credential fallback (branch 2 returns ''), but _has_explicit_pool_credentials
(branch 3) calls read_credential_pool, which falls back to the GLOBAL-root
auth.json via get_default_hermes_root() — and that reads os.environ['HERMES_HOME']
DIRECTLY, not the thread-local/scoped home. Under suite ordering HERMES_HOME
pointed at the shared persistent test state dir, where an earlier test had
persisted an openrouter credential_pool entry (source: env:OPENROUTER_API_KEY)
into auth.json. The global-root fallback found that leaked entry, so
_provider_has_key('openrouter') returned True and the assertion failed.
Fix: monkeypatch.setenv('HERMES_HOME', <tmp base>) so the global-root fallback
resolves to this test's own empty tmp dir with no leaked auth.json. Test-only;
no product change. Verified: passes in isolation AND the target test now passes
under the full suite (the only remaining full-suite reds were unrelated
subprocess-timeout SIGKILLs in test_tls_support under load, which pass on re-run).
* test(#4740): retry config-probe subprocesses in test_tls_support under load
The 3 TestTLSConfigFlag tests spawn a 'python -c' subprocess that imports
api.config (heavyweight) with a 10s timeout. Under the fully parallel full
suite the box can be saturated enough that the import exceeds 10s and the
runner SIGKILLs the child (returncode -9) — a pure resource-contention flake
(passes in isolation). Add _run_config_probe(): 60s timeout + retry on
TimeoutExpired/SIGKILL, returning a real non-zero exit immediately so genuine
failures still surface. Zero-flake-tolerance sweep (#4740).
---------
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
test_tls_support.py E2E tests have flaked repeatedly across releases. Root cause:
_find_free_port() binds port 0, reads the port, CLOSES the socket, then returns —
leaving a TOCTOU window where the OS reassigns that port (common under the 9-shard
parallel suite + concurrent agents) before server.py binds it. Server fails to bind,
_wait_for_server polls a dead process for the full 8s, test times out.
Fix (test-only): new _start_and_wait() retries bring-up on a FRESHLY chosen port
(defeats the race), _wait_for_server bails the moment proc.poll() shows the subprocess
died (fast retry signal, not a slow timeout), timeout bumped 8s->30s for cold imports
under load, and server output is captured into the AssertionError on hard failure.
Verified deterministic: 4 consecutive clean runs + a run under 50-held-port contention.
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
* stage-3664: Windows pytest harness hardening (test-only batch #4254/4255/4256/4257/4259)
* test(#3664): Windows pytest-harness compatibility batch
Combines 5 rodboev test-only PRs (#4254/#4255/#4256/#4257/#4259), all under tests/.
Linux assertion paths preserved at full strictness; relaxations + new markers are
Windows/no-fork gated. Codex SAFE + Opus SHIP + changed tests green (cascade-only
full-suite noise is the box artifact). No version stamp (tests-only, Nathan rule).
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
---------
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
* test(windows): hide test helper console windows (#3706)
* test(windows): use CREATE_NO_WINDOW constant (#3706)
* test(windows): hide test-helper console windows on Windows (#3710fixes#3706)
@rodboev. Long-lived test helper subprocesses (test server, browser-smoke, TLS helper,
ctl helpers) now spawn with CREATE_NO_WINDOW on Windows so a local pytest run doesn't
pop focus-stealing console windows. sys.platform=='win32' guarded → no-op on macOS/Linux
(expands to **{}). Test-only, no production code, no user impact. + CHANGELOG v0.51.301.
---------
Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <[email protected]>
Add optional HTTPS support controlled by two env vars:
HERMES_WEBUI_TLS_CERT=/path/to/cert.pem
HERMES_WEBUI_TLS_KEY=/path/to/key.pem
- Wraps server socket with ssl.SSLContext (min TLSv1.2)
- Dynamic scheme detection for startup messages (http:// vs https://)
- Graceful fallback to HTTP if cert loading fails — server never crashes
due to bad TLS config, just prints a warning and continues
- Auth cookie Secure flag already set when HTTPS is detected via getpeercert
- 6 end-to-end tests: config flags, HTTPS handshake, HTTP still works,
fallback on bad paths
Addresses #191 (HTTPS support issue).