ulysses/src
Ahmed Dlshad 8f5e36a079
fix(routes): log and cleanly 500 on unreadable HTML page (#4637)
* fix(routes): serve 404 instead of 500 when an HTML page file is missing

_serve_html_with_nonce opened the HTML file with no error handling, and
callers such as /backgrounds and /login pass their paths in with no
existence check, so a missing or unreadable file raised an unhandled
OSError that surfaced as a 500. Wrap the read and raise HTTPException(404)
instead; the normal render path (CSP-nonce substitution) is unchanged.

Fixes #4594

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(routes): distinguish missing page (404) from read failure (500)

The previous fix caught a broad OSError and returned 404 for every
failure, which masks real server-side problems (permission errors, I/O
failures) as "not found" and lets them slip past error alerting. Split
FileNotFoundError (genuine 404) from other OSError, which now logs the
exception and returns a generic 500 — without leaking the OS error
string or file path into the response body.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(routes): treat unreadable bundled HTML page as logged 500, not 404

Per PR #4637 review: every caller of the page-render helper serves a fixed,
server-owned template (index/login/backgrounds), never a client-supplied
path. So a missing or unreadable file is a server fault (broken deployment),
not a client "not found" — a 404 there mislabels a server error and hides a
missing core template from 5xx alerting, contradicting the OSError->500
rationale this PR is built on. Collapse both branches into a single logged,
leak-free 500.

Move the helper to src.app_helpers.serve_html_with_nonce so the behavior can
be unit-tested without importing the whole app (app.py is the slim
orchestrator; the test harness stubs src.database, so importing app in tests
is not viable). Add tests pinning missing/unreadable -> 500 (not 404) and
nonce injection on the happy path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:12:32 +02:00
..
agent_tools Merge origin/dev into main 2026-06-21 11:08:50 +00:00
search refactor(search): make src analytics a service shim (#2264) 2026-06-04 18:57:24 +02:00
action_intents.py fix(agent): honor explicit web search requests 2026-06-15 15:02:10 +09:00
agent_loop.py fix ask-user choices across reloads (#4669) 2026-06-22 20:49:49 +02:00
agent_runs.py Agent stream: 10s heartbeat keepalive on the SSE subscribe so long-running thinking models dont drop the connection 2026-06-19 00:34:30 +00:00
ai_interaction.py refactor(tools): move session tools to the agent_tools registry (#4454) 2026-06-19 11:55:22 +02:00
api_key_manager.py fix(security): restrict API-key encryption key file to 0o600 2026-06-15 15:00:11 +09:00
app_helpers.py fix(routes): log and cleanly 500 on unreadable HTML page (#4637) 2026-06-23 16:12:32 +02:00
app_initializer.py feat(memory): add provider interface (#72) 2026-06-04 16:26:11 +01:00
assistant_log.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
auth_helpers.py fix(auth): gate api tokens from user routes (#2992) 2026-06-07 12:55:01 +02:00
bg_jobs.py feat(agent): add manage_bg_jobs tool to inspect and kill background bash jobs (#4577) 2026-06-19 00:28:22 -07:00
bg_monitor.py fix: drop thinking deltas from background agent loops 2026-06-15 15:03:09 +09:00
builtin_actions.py Cookbook model workflow fixes 2026-06-21 11:02:35 +00:00
builtin_mcp.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
caldav_sync.py Harden CalDAV write-back with retries (#1193) 2026-06-15 15:59:31 +09:00
caldav_writeback.py Harden CalDAV write-back with retries (#1193) 2026-06-15 15:59:31 +09:00
chat_handler.py Scope vision model resolution by owner (#3009) 2026-06-07 12:39:02 +02:00
chat_helpers.py fix(chat): keep balanced trailing ')' when extracting URLs (#3406) 2026-06-08 21:33:29 +02:00
chat_processor.py fix(chat): stabilize system prompt, sequence memory extraction, and send stable session id to preserve KV cache (#3360) 2026-06-09 22:46:54 +01:00
chatgpt_subscription.py Fix model endpoint route test regressions 2026-06-09 10:16:38 +09:00
chroma_client.py fix: ChromaDB unreachable blocks app startup for 30-60s (#326) (#476) 2026-06-01 22:22:41 +09:00
cleanup_service.py Replace cleanup service datetime.utcnow calls (#1494) 2026-06-03 14:14:27 +09:00
config.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
constants.py Merge origin/dev into main 2026-06-21 11:08:50 +00:00
context_budget.py fix(agent): don't let a materialized default budget defeat context-window scaling (#4122) 2026-06-15 15:17:28 +09:00
context_compactor.py fix(research): keep Discuss chats grounded on their report (#4006) 2026-06-15 20:31:57 +09:00
cookbook_serve_lifecycle.py fix(cookbook): only persist successfully stopped scheduled serves (#4267) 2026-06-15 17:30:18 +02:00
copilot.py feat(provider): add GitHub Copilot provider with device-flow auth (#1480) 2026-06-04 21:13:14 +02:00
database.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
deep_research.py fix(research): track analyzed URLs separately (#3125) 2026-06-10 12:08:22 +01:00
document_actions.py fix: document tidy crashes on a duplicate with NULL timestamps (#1772) 2026-06-03 13:23:01 +09:00
document_processor.py Settings overhaul + UI polish pass 2026-06-10 15:15:13 +09:00
email_thread_parser.py Ignore non-string email thread bodies (#1654) 2026-06-03 14:06:31 +09:00
embedding_lanes.py fix(embeddings): survive numpy embeddings when restoring a reset lane (#3410) 2026-06-09 10:40:17 +02:00
embeddings.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
endpoint_resolver.py Merge origin/dev into main 2026-06-21 11:08:50 +00:00
event_bus.py refactor(constants): single source of truth for data dir (#3368) 2026-06-08 09:58:52 +02:00
exceptions.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
generated_images.py refactor(constants): single source of truth for data dir (#3368) 2026-06-08 09:58:52 +02:00
goal_based_extractor.py fix(deep-research): wrap fetched webpage content in untrusted-context sandbox 2026-06-06 03:37:10 -06:00
integrations.py fix(endpoints): normalize URL handling (#4338) 2026-06-16 03:59:18 +01:00
llm_core.py fix: Images cannot be seen by model that is vision capable (#4726) 2026-06-23 10:32:57 +02:00
markitdown_runtime.py Settings overhaul + UI polish pass 2026-06-10 15:15:13 +09:00
mcp_manager.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
mcp_oauth.py feat(mcp): add Streamable HTTP transport with OAuth 2.0 (#1033) 2026-06-05 02:40:52 +02:00
memory.py refactor(memory): canonicalize memory imports (#50) 2026-06-04 05:31:15 +01:00
memory_provider.py feat(memory): add provider interface (#72) 2026-06-04 16:26:11 +01:00
memory_vector.py fix: split Chroma embedding lanes (#3046) 2026-06-06 03:17:19 -06:00
model_context.py fix(endpoints): normalize URL handling (#4338) 2026-06-16 03:59:18 +01:00
model_discovery.py fix(startup): ping real endpoints in warmup/keepalive (#3641) 2026-06-10 19:21:45 +02:00
office_doc.py Merge remote-tracking branch 'origin/dev' into test-main-dev-merge-20260615 2026-06-15 21:20:15 +09:00
optional_deps.py fix(image): patch realesrgan torchvision compatibility (#4110) 2026-06-15 15:16:41 +09:00
pdf_form_doc.py refactor(tools): extract document tools to handle registry (#3666) 2026-06-10 10:41:52 +02:00
pdf_forms.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
pdf_runtime.py Show a clear message when PyMuPDF is missing 2026-06-01 18:27:17 +09:00
personal_docs.py fix(auth): clean up rename and null-owner ownership (#4340) 2026-06-16 03:33:02 +01:00
preset_manager.py fix(presets): persist presets atomically to avoid corruption on crash (#2169) 2026-06-08 19:16:37 +02:00
prompt_security.py fix(security): harden untrusted_context_message against delimiter spoofing (#3086) 2026-06-07 22:15:50 +01:00
rag_manager.py refactor(constants): single source of truth for data dir (#3368) 2026-06-08 09:58:52 +02:00
rag_singleton.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
rag_vector.py fix(auth): clean up rename and null-owner ownership (#4340) 2026-06-16 03:33:02 +01:00
rate_limiter.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
readiness.py feat: add /api/ready readiness probe (DB, data dir, local-first) (#1200) 2026-06-02 23:33:22 +09:00
reminder_personas.py Settings overhaul + UI polish pass 2026-06-10 15:15:13 +09:00
request_models.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
research_handler.py fix(research): migrate active task owners on rename (#3618) 2026-06-11 01:17:02 +02:00
research_utils.py Treat non-string research summaries as low quality 2026-06-03 13:42:24 +09:00
runtime_paths.py feat(paths): abstract runtime path logic for frozen distribution packages (#969) 2026-06-15 17:44:10 +01:00
secret_storage.py refactor(constants): single source of truth for data dir (#3368) 2026-06-08 09:58:52 +02:00
service_health.py feat(diagnostics): add consolidated service health endpoint for degraded-state reporting (#964) 2026-06-09 16:00:24 +01:00
session_actions.py fix(sessions): keep fresh chats during auto tidy (#1871) 2026-06-09 01:06:20 +01:00
session_search.py fix(search): batch FTS hit lookups into one query (N+1) (#3909) 2026-06-11 16:31:54 +02:00
settings.py Merge remote-tracking branch 'origin/dev' into test-main-dev-merge-20260615 2026-06-15 21:20:15 +09:00
settings_scrub.py fix(settings): scrub camelCase secret keys (#3707) 2026-06-11 12:53:33 +02:00
task_endpoint.py Cookbook model workflow fixes 2026-06-21 11:02:35 +00:00
task_scheduler.py fix(security): redact credential-bearing URLs and PII from logs (#4750) 2026-06-22 23:12:39 +02:00
teacher_escalation.py fix(kimi): resolve Kimi Code API 403 errors and User-Agent restrictions (#3549) 2026-06-15 15:56:54 +09:00
text_helpers.py fix: normalize Gemma 4 thought-channel output (#2224) 2026-06-04 19:26:58 +02:00
tls_overrides.py Support extra CA bundle for private-CA LLM providers (#769) 2026-06-04 13:18:50 +01:00
tool_execution.py refactor(tools): move session tools to the agent_tools registry (#4454) 2026-06-19 11:55:22 +02:00
tool_implementations.py Merge origin/dev into main 2026-06-21 11:08:50 +00:00
tool_index.py fix ask-user choices across reloads (#4669) 2026-06-22 20:49:49 +02:00
tool_parsing.py Clear remaining CodeQL path and parser alerts 2026-06-22 02:45:05 +00:00
tool_policy.py fix(agent): enforce guide-only tool policy (#3088) 2026-06-06 18:48:24 -06:00
tool_schemas.py fix ask-user choices across reloads (#4669) 2026-06-22 20:49:49 +02:00
tool_security.py feat(agent): add manage_bg_jobs tool to inspect and kill background bash jobs (#4577) 2026-06-19 00:28:22 -07:00
tool_utils.py refactor(tools): consolidate duplicated _truncate and get_mcp_manager into src/tool_utils (#3478) 2026-06-09 01:05:30 +02:00
topic_analyzer.py Topics: hydrate session history before analysis 2026-06-02 20:44:27 +09:00
upload_handler.py fix(uploads): migrate upload ownership on rename (#3617) 2026-06-11 16:01:04 +02:00
upload_limits.py refactor(uploads): centralize upload byte-limits in upload_limits.py (#3364) (#3518) 2026-06-09 01:24:30 +02:00
url_safety.py fix: check_outbound_url crashes on a truthy non-string URL (#1623) 2026-06-03 08:59:49 +09:00
url_security.py Reapply "Merge branch 'main' of github.com:pewdiepie-archdaemon/odysseus" 2026-06-03 22:47:00 +09:00
user_time.py fix(chat): stabilize system prompt, sequence memory extraction, and send stable session id to preserve KV cache (#3360) 2026-06-09 22:46:54 +01:00
visual_report.py security: sanitize rendered research-report HTML (#364) 2026-06-04 13:42:49 +01:00
webhook_manager.py fix(webhooks): keep references to in-flight delivery tasks (#3859) 2026-06-11 15:53:52 +02:00
youtube_handler.py fix(youtube): consolidate duplicate handler 2026-06-15 15:03:41 +09:00