2026-04-05 03:07:05 +00:00
|
|
|
"""
|
|
|
|
|
Hermes Web UI -- Optional state.db sync bridge.
|
|
|
|
|
|
|
|
|
|
Mirrors WebUI session metadata (token usage, title, model) into the
|
|
|
|
|
hermes-agent state.db so that /insights, session lists, and cost
|
|
|
|
|
tracking include WebUI activity.
|
|
|
|
|
|
|
|
|
|
This is opt-in via the 'sync_to_insights' setting (default: off).
|
|
|
|
|
All operations are wrapped in try/except -- if state.db is unavailable,
|
|
|
|
|
locked, or the schema doesn't match, the WebUI continues normally.
|
|
|
|
|
|
|
|
|
|
The bridge uses absolute token counts (not deltas) because the WebUI
|
|
|
|
|
Session object already accumulates totals across turns. This avoids
|
|
|
|
|
any double-counting risk.
|
|
|
|
|
"""
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
import logging
|
2026-04-05 03:07:05 +00:00
|
|
|
import os
|
|
|
|
|
from pathlib import Path
|
2026-06-01 08:59:10 +00:00
|
|
|
from typing import Optional
|
2026-04-05 03:07:05 +00:00
|
|
|
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
2026-04-05 03:07:05 +00:00
|
|
|
|
2026-06-01 08:59:10 +00:00
|
|
|
def _get_state_db(profile: Optional[str] = None):
|
2026-05-24 18:57:40 +00:00
|
|
|
"""Get a SessionDB instance for a profile's state.db.
|
|
|
|
|
|
|
|
|
|
When ``profile`` is provided the function resolves *that* profile's
|
|
|
|
|
home directory directly (via ``_resolve_profile_home_for_name``).
|
|
|
|
|
If resolution fails (unknown profile name, IO error, etc.) the
|
|
|
|
|
function returns ``None`` rather than silently falling back to
|
|
|
|
|
``HERMES_HOME`` — silently routing the write to the wrong DB
|
|
|
|
|
would defeat the point of the explicit-profile path (#2762).
|
|
|
|
|
|
|
|
|
|
When ``profile`` is None it falls back to the TLS-based
|
|
|
|
|
``get_active_hermes_home()`` lookup for backward compatibility,
|
|
|
|
|
with a final ``HERMES_HOME`` fallback only on that path. TLS may be
|
|
|
|
|
unset in background/worker threads, in which case the lookup falls
|
|
|
|
|
through to the process-global active profile and can write to the
|
|
|
|
|
wrong DB. Callers that know the session's profile (e.g.
|
|
|
|
|
``sync_session_usage`` after a stream completes on a background
|
|
|
|
|
thread) should pass it explicitly to avoid that race.
|
|
|
|
|
|
|
|
|
|
Returns None if hermes_state is not importable, the explicit
|
|
|
|
|
profile cannot be resolved, or the DB is unavailable. Each caller
|
|
|
|
|
is responsible for calling db.close() when done.
|
2026-04-05 03:07:05 +00:00
|
|
|
"""
|
|
|
|
|
try:
|
2026-04-05 03:08:20 +00:00
|
|
|
from hermes_state import SessionDB
|
2026-04-05 03:07:05 +00:00
|
|
|
except ImportError:
|
|
|
|
|
return None
|
|
|
|
|
|
2026-05-24 18:57:40 +00:00
|
|
|
if profile is not None:
|
|
|
|
|
# Explicit-profile path — a resolution failure here MUST NOT
|
|
|
|
|
# silently fall back to HERMES_HOME or the caller's "write to
|
|
|
|
|
# the named profile" contract is broken (the original #2762
|
|
|
|
|
# symptom: writes leaking into the wrong profile's state.db).
|
|
|
|
|
#
|
|
|
|
|
# Defense-in-depth (per #2827 maintainer review): validate the
|
|
|
|
|
# name shape BEFORE handing it to ``_resolve_profile_home_for_name``.
|
|
|
|
|
# The resolver itself rarely raises — for an invalid-but-non-
|
|
|
|
|
# malicious name (e.g. one that fails ``_PROFILE_ID_RE``) it
|
|
|
|
|
# quietly returns ``_DEFAULT_HERMES_HOME``, which is the exact
|
|
|
|
|
# leak we're trying to prevent on the explicit-profile path.
|
|
|
|
|
# Validating up-front turns that quiet leak into an explicit
|
|
|
|
|
# "refuse + log + return None" so the contract is "write to
|
|
|
|
|
# the EXACT named profile, or write nowhere."
|
|
|
|
|
try:
|
|
|
|
|
from api.profiles import (
|
|
|
|
|
_resolve_profile_home_for_name,
|
|
|
|
|
_PROFILE_ID_RE,
|
|
|
|
|
_is_root_profile,
|
|
|
|
|
)
|
|
|
|
|
if not (_is_root_profile(profile) or _PROFILE_ID_RE.fullmatch(profile)):
|
|
|
|
|
logger.warning(
|
|
|
|
|
"state_sync: refusing invalid profile name %r — skipping "
|
|
|
|
|
"write rather than leaking to the default state.db (#2762).",
|
|
|
|
|
profile,
|
|
|
|
|
)
|
|
|
|
|
return None
|
|
|
|
|
hermes_home = Path(_resolve_profile_home_for_name(profile)).expanduser().resolve()
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.warning(
|
|
|
|
|
"state_sync: could not resolve profile %r — skipping write rather "
|
|
|
|
|
"than leaking to the active profile (#2762).", profile,
|
|
|
|
|
)
|
|
|
|
|
return None
|
|
|
|
|
else:
|
|
|
|
|
# Implicit / TLS-fallback path — preserves pre-#2762 behavior
|
|
|
|
|
# for any caller that doesn't pass profile= explicitly.
|
|
|
|
|
try:
|
|
|
|
|
from api.profiles import get_active_hermes_home
|
|
|
|
|
hermes_home = Path(get_active_hermes_home()).expanduser().resolve()
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.debug("Failed to resolve hermes home, using default")
|
|
|
|
|
hermes_home = Path(os.getenv('HERMES_HOME', str(Path.home() / '.hermes')))
|
2026-04-05 03:07:05 +00:00
|
|
|
|
|
|
|
|
db_path = hermes_home / 'state.db'
|
|
|
|
|
if not db_path.exists():
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
try:
|
2026-04-05 03:08:20 +00:00
|
|
|
return SessionDB(db_path)
|
2026-04-05 03:07:05 +00:00
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to open state.db")
|
2026-04-05 03:07:05 +00:00
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
2026-06-01 08:59:10 +00:00
|
|
|
def sync_session_start(session_id: str, model=None, profile: Optional[str] = None) -> None:
|
2026-04-05 03:07:05 +00:00
|
|
|
"""Register a WebUI session in state.db (idempotent).
|
|
|
|
|
Called when a session's first message is sent.
|
2026-05-24 18:57:40 +00:00
|
|
|
|
|
|
|
|
``profile`` lets the caller name the target state.db explicitly,
|
|
|
|
|
avoiding the TLS-vs-background-thread mismatch in #2762. When
|
|
|
|
|
omitted, the active profile is resolved from TLS (then process
|
|
|
|
|
globals) as before.
|
2026-04-05 03:07:05 +00:00
|
|
|
"""
|
2026-05-24 18:57:40 +00:00
|
|
|
db = _get_state_db(profile=profile)
|
2026-04-05 03:08:20 +00:00
|
|
|
if not db:
|
|
|
|
|
return
|
2026-04-05 03:07:05 +00:00
|
|
|
try:
|
|
|
|
|
db.ensure_session(
|
|
|
|
|
session_id=session_id,
|
|
|
|
|
source='webui',
|
|
|
|
|
model=model,
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to sync session start to state.db")
|
2026-04-05 03:08:20 +00:00
|
|
|
finally:
|
|
|
|
|
try:
|
|
|
|
|
db.close()
|
|
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to close state.db")
|
2026-04-05 03:07:05 +00:00
|
|
|
|
|
|
|
|
|
2026-04-05 06:54:58 +00:00
|
|
|
def sync_session_usage(session_id: str, input_tokens: int=0, output_tokens: int=0,
|
2026-06-01 08:59:10 +00:00
|
|
|
estimated_cost=None, model=None, title: Optional[str] = None,
|
|
|
|
|
message_count: Optional[int] = None, profile: Optional[str] = None) -> None:
|
2026-04-05 03:07:05 +00:00
|
|
|
"""Update token usage and title for a WebUI session in state.db.
|
|
|
|
|
Called after each turn completes. Uses absolute=True to set totals
|
|
|
|
|
(the WebUI Session already accumulates across turns).
|
2026-05-24 18:57:40 +00:00
|
|
|
|
|
|
|
|
``profile`` lets the caller name the target state.db explicitly,
|
|
|
|
|
which is what fixes #2762: this function is invoked from the
|
|
|
|
|
agent streaming worker thread, where the request-thread's TLS
|
|
|
|
|
profile context has not been propagated. Without an explicit
|
|
|
|
|
profile, the TLS lookup falls back to the process-global active
|
|
|
|
|
profile and writes the session's usage to the wrong state.db
|
|
|
|
|
(e.g. ``hiyuki``'s instead of the cookie-switched ``maiko``'s).
|
2026-04-05 03:07:05 +00:00
|
|
|
"""
|
2026-05-24 18:57:40 +00:00
|
|
|
db = _get_state_db(profile=profile)
|
2026-04-05 03:08:20 +00:00
|
|
|
if not db:
|
|
|
|
|
return
|
2026-04-05 03:07:05 +00:00
|
|
|
try:
|
|
|
|
|
# Ensure session exists first (idempotent)
|
|
|
|
|
db.ensure_session(session_id=session_id, source='webui', model=model)
|
|
|
|
|
# Set absolute token counts
|
|
|
|
|
db.update_token_counts(
|
|
|
|
|
session_id=session_id,
|
|
|
|
|
input_tokens=input_tokens,
|
|
|
|
|
output_tokens=output_tokens,
|
|
|
|
|
estimated_cost_usd=estimated_cost,
|
|
|
|
|
model=model,
|
|
|
|
|
absolute=True,
|
|
|
|
|
)
|
2026-04-05 03:08:20 +00:00
|
|
|
# Update title if we have one, using the public API
|
2026-04-05 03:07:05 +00:00
|
|
|
if title:
|
|
|
|
|
try:
|
2026-04-05 03:08:20 +00:00
|
|
|
db.set_session_title(session_id, title)
|
2026-04-05 03:07:05 +00:00
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to sync session title to state.db")
|
2026-04-07 05:56:27 +00:00
|
|
|
# Update message count
|
|
|
|
|
if message_count is not None:
|
|
|
|
|
try:
|
|
|
|
|
def _set_msg_count(conn):
|
|
|
|
|
conn.execute(
|
|
|
|
|
"UPDATE sessions SET message_count = ? WHERE id = ?",
|
|
|
|
|
(message_count, session_id),
|
|
|
|
|
)
|
|
|
|
|
db._execute_write(_set_msg_count)
|
|
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to sync message count to state.db")
|
2026-04-05 03:07:05 +00:00
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to sync session usage to state.db")
|
2026-04-05 03:08:20 +00:00
|
|
|
finally:
|
|
|
|
|
try:
|
|
|
|
|
db.close()
|
|
|
|
|
except Exception:
|
security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
* security: fix bandit security issues (B310, B324)
- Add usedforsecurity=False to MD5 hash in gateway_watcher.py
- Add URL scheme validation to prevent file:// access in config.py
- Add URL validation to bootstrap.py health check
- Add nosec comments where runtime validation exists
* fix: handle ConnectionResetError gracefully and add debug logging
- Add QuietHTTPServer class to suppress noisy connection reset errors
caused by clients disconnecting abruptly (fixes log spam from
'ConnectionResetError: [Errno 54] Connection reset by peer')
- Replace silent 'pass' statements with logger.debug() calls across
api/auth.py, api/config.py, api/gateway_watcher.py, api/models.py,
and api/onboarding.py for better observability during troubleshooting
- All tests pass (25 passed in test_regressions.py)
* chore: add debug logging to profiles and routes modules
- Replace silent 'pass' statements with logger.debug() calls in
api/profiles.py for better error visibility during profile switching
and module patching
- Add logger initialization to api/routes.py
* security: fix B110 bare except/pass issues (bandit security scan)
- Replace bare except/pass patterns with logger.debug() calls
- Fixes CWE-703 (improper check/handling of exceptional conditions)
- Files affected: routes.py, state_sync.py, streaming.py, workspace.py, server.py
- All tests pass successfully
* security: bandit fixes B310/B324/B110 + QuietHTTPServer (#354)
- api/gateway_watcher.py: MD5 usedforsecurity=False (B324)
- api/config.py, bootstrap.py: URL scheme validation before urlopen (B310)
- 12 files: replace bare except/pass with logger.debug() (B110)
- server.py: QuietHTTPServer suppresses client disconnect log noise
- server.py: fix sys.exc_info() (was traceback.sys.exc_info(), impl detail)
- tests/test_sprint43.py: 19 new tests covering all security fixes
- CHANGELOG.md: v0.50.14 entry; 841 tests total (up from 822)
---------
Co-authored-by: lawrencel1ng <lawrence.ling@global.ntt>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-04-13 18:11:56 +00:00
|
|
|
logger.debug("Failed to close state.db")
|