Commit Graph
2592 Commits
Author SHA1 Message Date
RaresKeYandLéo c6d76b9a9b fix(security): refresh client trust and publish validated SearXNG images
Repair SearXNG system and certifi stores, validate native amd64/arm64 runtime images through Compose, and publish the exact verified artifacts through a trusted CI job. Adopt released Python, certifi, grpcio, uv and Docker CLI trust fixes, with strict controls for all fourteen public incident chains.

Part of #6784 and #6790.

Co-authored-by: Léo <leograndcontact@gmail.com>
2026-10-23 22:32:33 +00:00
GrzegorzandClaude Opus 5.5 f8e043e8ca fix(approvals): seal approved bash/python and file writes in the agent workspace when no workspace is set (#6705)
#6683 made an exact approval seal a launch boundary (and a filesystem root)
in the request's workspace, but only when a workspace is bound. Agent mode
with no folder picked is the default, and there the approval still sealed
nothing, so "Allow" always ended in "Approved action has no sealed
process/job identity" (bash/python) or "Approved filesystem action has no
sealed resource identity" (write_file). In Docker every agent turn carries
the backend runtime context, so bash and write_file always ask for approval
and never ran.

With no workspace, seal the root in the agent workspace, which is where
agent_cwd() already runs bash/python in that case. Inherited (child)
authorities still cannot widen.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 13:19:04 -06:00
Isharakandisharak7m 98a16242c6 fix(security): add SSRF validation to manage_endpoints agent tool (#6327)
The manage_endpoints agent tool accepts arbitrary user-supplied base_urls
and writes them to the database without calling check_outbound_url(),
while the HTTP route (POST /api/model-endpoints) enforces full SSRF
hardening. A prompt-injection payload smuggled into a skill, note, fetched
page, or email could instruct the model to register a cloud-metadata or
internal-network endpoint via this tool path.

Add the same check_outbound_url() guard used by the HTTP route to the
agent tool's 'add' action. Also sanitize the error message in the except
block to avoid leaking raw exception text.

Add 8 regression tests covering: cloud metadata, non-HTTP schemes,
loopback (local-first), strict mode, safe URLs, empty URLs, gopher
scheme, and error message sanitization.

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
2026-10-23 13:18:59 -06:00
IsharakSantoshkumarpuppalaisharak7m
0dbf457c00 fix(security): block SSRF via user-supplied model endpoint URLs (#6316)
* fix: block SSRF via user-supplied model endpoint URLs

* fix(test): stub DNS in loopback SSRF tests for deterministic results

Replace environment-dependent test_loopback_always_rejected with two
deterministic tests using a stub resolver:
- test_loopback_accepted_by_default (local-first, block_private=False)
- test_loopback_rejected_in_strict_mode (block_private=True)

The old test only passed when localhost resolved to ::1 (hit is_reserved),
not because loopback was actually always rejected.

Co-Authored-By: Santoshkumarpuppala

* fix: guard PATCH base_url against SSRF and add ipv6 loopback coverage

---------

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
2026-10-23 13:18:54 -06:00
Raul JuarezandRaul b4ae7ebcc4 feat(agent): expose chat history with existing chat scope (#6443)
Co-authored-by: Raul <9117159+raultcj@users.noreply.github.com>
2026-10-23 13:18:49 -06:00
RaresKeY 01566b158e fix(ci): lowercase container image repository names (#6802) 2026-10-22 17:08:05 +01:00
RaresKeY a98013dd33 Merge pull request #6785 from RaresKeY/fix/emudhra-ca-trust
fix: refresh outbound HTTPS trust and installer bootstrap
2026-10-22 11:18:07 +01:00
RaresKeY 77a02c30ff fix(security): verify deployed trust before dependency work 2026-10-21 21:40:05 +00:00
RaresKeY cd9f1f734f fix(security): detect incident CAs in custom trust stores
Reject the published compromised intermediates and cross-signed G3 issuer when supplied as trust anchors. Add explicit CA-override inspection and offline chain regressions with a fixed verification time and affected positive control.
2026-10-21 20:48:34 +00:00
RaresKeY 5d0a219ede fix: distrust incident certificates in Chromium and gRPC 2026-10-21 20:09:54 +00:00
RaresKeY c4fdaf59b3 fix(tls): accept hashed non-CA certificates during trust checks 2026-10-21 18:59:02 +00:00
RaresKeY df1c2c8b19 fix: refresh outbound HTTPS trust and installer bootstrap 2026-10-21 18:27:05 +00:00
Alexandre Teixeira 8877273e19 Merge pull request #6742 from odysseus-dev/codex/review-7011-email-export-20261015
feat(email): export selected messages as EML or print to PDF
2026-10-20 16:37:53 +01:00
Alexandre Teixeira 377070ab79 fix(email): propagate preflight safety failure across all mailbox groups
- Propagate preflight HTTPException(status_code=502) regardless of whether other mailbox groups exported messages into the temporary ZIP
- Guarantee temporary file cleanup via SpooledTemporaryFile.close() on preflight failure
- Preserve partial success (HTTP 200) for genuinely missing mail
- Add executable tests for multi-group preflight failure orderings, missing mail, and zero body fetches
2026-10-20 15:36:16 +01:00
Alexandre Teixeira f06ec5d91f Merge branch 'upstream/dev' into fix/pr-6742-email-export 2026-10-20 15:01:55 +01:00
Alexandre Teixeira 057ae92c17 fix(email): support case-insensitive IMAP atoms and portable browser discovery
- Make _uid_from_fetch_meta case-insensitive with re.IGNORECASE matching size extraction
- Remove hardcoded developer home paths from test_email_library_print_browser.cjs
- Implement standard Playwright Chromium discovery with environment variable overrides and actionable launch failures
- Add executable tests for uppercase, lowercase, mixed-case IMAP atoms, malformed metadata, and preflight security
2026-10-20 15:00:13 +01:00
Alexandre Teixeira 75df766358 fix(email): harden RFC822.SIZE preflight validation and ignore duplicate IMAP records
- Require valid RFC822.SIZE preflight metadata for every message before body FETCH
- Fail safely with HTTP 502 without body fetching on NO, malformed, or inconsistent sizes
- Distinguish missing mail (HTTP 404) from bad size preflight (HTTP 502)
- Discard duplicate IMAP response records for already-processed UIDs in batch loop
- Correct print notification toast to "Prepared N emails for printing; M unavailable"
- Add dedicated Playwright browser regression test script to repository test suite
- Add request-level tests for preflight NO, empty, partial, malformed, and duplicates
2026-10-20 14:09:47 +01:00
Alexandre Teixeira c7d1555eea fix(email): resolve memory safety, print rendering, and accounting defects
- Use SpooledTemporaryFile with 32 MiB spool threshold for export ZIP archives
- Add IMAP size preflight via (UID RFC822.SIZE) and cap batch payload at 10 MiB
- Enforce 64 MiB per-message ceiling and fail closed with 500 on corrupted ZIP
- Stream spooled archive chunks with generator cleanup on disconnect/cancellation
- Bypass ZIP creation for single raw EML message downloads
- Memoize account ownership checks per request to eliminate N+1 database queries
- Replace interactive image placeholders in print view with clean text notices
- Strip interactive buttons, icons, and image actions from print document
- Implement partial print success policy printing loaded items and reporting omitted
- Harden print iframe lifecycle with window afterprint listener and fallback timer
- Correct mid-batch exception accounting so exported plus skipped equals requested
- Add executable behavioral tests for limits, mid-batch accounting, and memoization
2026-10-20 11:38:12 +01:00
Alexandre Teixeira 550ac015eb fix(email): enforce account ownership and correct partial failure accounting
- Validate account ownership with _assert_owns_account for every account_id
- Deduplicate items in selection to prevent duplicate files and skewed accounting
- Fix exception handling in IMAP batching to avoid double-counting on partial failures
- Re-raise HTTPException so 413 memory cap errors are not swallowed
- Remove unused addField helper in emailLibrary print exporter
- Add behavioral test suite covering empty/oversized validation, rfc822 export,
  zip export, partial failure/dedup, and cross-tenant account isolation
2026-10-20 10:35:30 +01:00
Alexandre Teixeira 8eaf742b43 fix(email): replace html2pdf with Print / save PDF and harden EML export
SAN-157 removed the html2pdf client library. The PDF export code added
in the original PR commit referenced the deleted library and would fail
at runtime. Replace the html2pdf-based _downloadSelectedEmailPdf with a
browser Print / save PDF workflow using a sandboxed iframe and
window.print(), matching the established pattern in document.js and
compare/index.js.

Changes:
- Replace _loadEmailHtml2Pdf and _downloadSelectedEmailPdf with
  _printSelectedEmails using a sandboxed iframe + contentWindow.print()
- Update menu label from 'PDF' to 'Print / save PDF'
- Add 512 MiB total size cap to /messages-download-bulk to prevent
  unbounded memory growth when exporting many large messages
- Update test assertions to verify the browser print pattern and
  confirm html2pdf is not referenced
- Add regression tests for size cap, selection count validation,
  non-numeric UID rejection, and partial batch failure accounting
2026-10-20 10:14:55 +01:00
Alexandre Teixeira 8363919aec Merge pull request #6736 from alteixeira20/docs/maintainer-handbook-governance-v1
docs(maintainers): add public governance handbook and review playbook
2026-10-20 09:58:01 +01:00
Alexandre Teixeira ae238b737f Merge pull request #6396 from Gr33ndev/dev
fix(ui): respect iOS safe areas, screen height and landscape layout
2026-10-20 01:12:33 +01:00
PR #6029 Reviewer 63e18a46c7 test(css): update snapshots for iOS safe-area layout 2026-10-20 01:01:35 +01:00
Alexandre Teixeira 268636c9aa Merge pull request #6473 from ShahabAhmed01/fix/scheduler-research-settings-guard-5049
fix(scheduler): fall back to defaults for non-numeric research settings
2026-10-19 23:44:18 +01:00
Gr33nbl00d b2613b2106 fix(ui): respect iOS safe areas, screen height and landscape layout 2026-10-19 19:43:53 +02:00
Alexandre Teixeira c1d90beeff fix(scheduler): catch OverflowError on non-finite research settings
Catch OverflowError in addition to TypeError and ValueError when converting
research_max_tokens, research_extraction_timeout_seconds, and
research_extraction_concurrency to int. Non-finite numbers parsed from JSON
(such as 1e309 or -1e309 representing float infinity) raise OverflowError on
int() conversion, which previously escaped the handler and crashed scheduled
research execution. Also add unit tests covering exponent overflow values.
2026-10-19 14:40:27 +01:00
Alexandre Teixeira 8946100695 Merge current dev into PR #6473
Preserve the contributor's original scheduler fix while integrating
current dev and its narrowly scoped secret-scanning configuration.
2026-10-19 14:40:26 +01:00
88772b3278 fix(tasks): apply the admin-only action policy in manage_tasks (#6358)
POST /api/tasks and the scheduler both refuse action tasks whose action
is in ADMIN_ONLY_TASK_ACTIONS (run_local, run_script, ssh_command,
cookbook_serve) for owners without admin task privileges: those actions
reach subprocess.run(shell=True) or SSH with no sandbox. The model-facing
manage_tasks tool applied neither check, so an agent could create or edit
such a task, resume it, or trigger it, and only the scheduler's
execution-time guard stood in the way (pausing the task after the fact).

Route the tool through the same src.task_action_policy helpers the HTTP
route uses: create checks the requested type/action, edit checks the task
as it would be after the edit (so an llm task cannot be flipped into a
shell action), and resume/run check the stored task. Admins, non-
privileged actions and llm/research tasks are unaffected; pause still
works for everyone since it only narrows.

Fixes #6021


Claude-Session: https://claude.ai/code/session_01UAB5sz5srMKR7rbeDFtdMH

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-10-19 14:04:10 +01:00
Boody 9712a54001 Merge pull request #6434 from PrinceThummar011/fix/5598-oauth-expired-state
fix(mcp): return dedicated expired page on unknown or expired OAuth callback state (#5598)
2026-10-16 22:05:31 +03:00
PrinceThummar011 15099ebabb refactor(mcp): unify OAuth flow resolution and distinguish missing params from expired state (#5598) 2026-10-16 17:16:15 +05:30
RaresKeY 0590edd4f2 Merge pull request #6744 from RaresKeY/docs/specs-bootstrap
docs(specs): routine specifications update
2026-10-16 08:00:46 +02:00
RaresKeY bead6a6797 docs(specs): routine specifications update 2026-10-15 16:52:16 +00:00
Léo 55b5b7f496 docs(maintainers): list website/ in the docs map and align CONTRIBUTING
Setup, configuration and deployment docs live in website/, which is
published as the docs site, but the map sent them to /docs and did not
list website/ at all. Add it, and drop the "when those paths are used"
hedge on /specs, which exists.

CODEOWNERS has no rules until #593 settles the per-area map; say so
instead of describing reviewers it does not list.

CONTRIBUTING.md still had a single maintainer curating main, which the
Release Maintainer section replaces. Name the Product Owner's GitHub
account and say where a community proposal starts, matching the
existing issue forms.
2026-10-15 18:09:36 +02:00
RaresKeY b97c1ee50f docs(maintainers): refine handbook and remove code of conduct 2026-10-15 15:31:56 +00:00
pewdiepie-archdaemon 6cf676dfe2 feat(email): export selected messages as email or PDF 2026-10-15 12:02:06 +00:00
Alexandre Teixeira a0137b47d1 docs(maintainers): publish governance handbook draft and review playbook
Adapt the agreed maintainer responsibilities and risk-based review policy for the public repository. Add evidence-driven security review, CodeQL triage, release guidance and a discoverable contributing link.
2026-10-15 11:16:52 +01:00
Robert Vind-GardoșandPR #6029 Reviewer c74f475679 fix(upload): honor no-login mode after account setup (#6528)
* fix(upload): honor no-login mode after account setup

* ci: refresh checks against the current dev base

* test(upload): add regression tests for unconfigured auth and no-login POST

* fix(upload): fail closed on missing auth_manager and preserve cross-user isolation

Enforce strict cross-user isolation so that authenticated users cannot access
files owned by other accounts when app.state.auth_manager is absent or None.
Fail closed with HTTP 503 for non-loopback requests when AUTH_ENABLED=true and
authentication infrastructure is unexpectedly unavailable, while preserving
intended single-user mode (AUTH_ENABLED=false) and intentional first-run setup
mode (auth_manager.is_configured=False).

* fix(upload): eliminate fail-open paths for unconfigured manager and loopback transport

- Eliminate early return on unconfigured auth_manager (Finding A): fail closed with HTTP 401 Setup required
- Eliminate loopback transport bypass when auth_manager is missing (Finding B): fail closed with HTTP 503
- Enforce strict ownership isolation: non-owners and legacy ownerless uploads require verified administrator access
- Add regression suites in tests/test_upload_no_login.py covering Finding A, Finding B, bearer tokens, and ownerless files
- Explicitly set AUTH_ENABLED=false for unauthenticated tests in tests/test_upload_routes_owner_scope.py

* fix(upload): prevent delegated API tokens from inheriting admin privileges and enforce upload scopes

- Prevent delegated bearer API credentials from inheriting interactive administrator privileges over other users' files or legacy ownerless files.
- Enforce granular upload scopes for delegated credentials: chat and documents:write for upload creation and vision OCR editing; chat, documents:read, and documents:write for downloads, thumbnails, and vision OCR reads.
- Reject requests with missing token owners or reserved sentinel identities (api, demo, system, internal-tool) with 403 Forbidden.
- Add comprehensive regression tests in tests/test_upload_no_login.py verifying delegated token scope isolation, sentinel rejection, owner isolation, and untouched OCR state on rejected edits.

---------

Co-authored-by: PR #6029 Reviewer <reviewer@odysseus-review.local>
2026-10-15 11:08:58 +01:00
Alexandre Teixeira b2e717e28f refactor(skills): extract evaluation and audit orchestration (#6711)
* refactor(skills): extract evaluation and audit orchestration

* chore(security): scope OpenAPI digest Gitleaks exception

* refactor(skills): establish domain-oriented service boundaries

* refactor(skills): address architecture review feedback

* fix(skills): restore prompt seams and harden signature contracts

* test(skills): restore ReDoS coverage and simplify API baseline
2026-10-15 09:30:16 +01:00
Alexandre TeixeiraandLéo f1a47f3812 refactor(notes): decompose Notes into feature-owned modules (#6713)
* refactor(notes): decompose Notes into feature-owned modules

* fix(notes): avoid HTML interpolation in reminder picker

* docs(notes): drop checkpoint archives, session logs and publication drafts

The N0-N6 tarballs and raw pytest/node logs are not read by any script or
test, and the logs carry absolute home-directory paths. Once squashed into
dev they would stay in history for good. notes-pr.md and notes-issue.md
were the drafts used to open #6712 and #6713, not documentation.

notes-validation.md keeps the counts, the checkpoint hashes and
implementation.sha256 as the record; local interpreter paths and the local
Docker image name are replaced with portable placeholders.

* fix(notes): keep the state store raw and stop masonry re-observing after close

- state: writes built from views (filter, spread, splice) stored nested
  read-only views in the store, so structuredClone on a stored note threw
  DataCloneError. Store writes now unwrap nested views.
- layout: a save that resolves after closePanel re-renders the leaving pane
  and re-created the masonry ResizeObserver that teardown had disposed.
  Skip creating it once Notes is closed.
- index.js: drop 30 imported or declared names that were never used and
  group the imports at the top. Import order is unchanged.
- Revert unrelated punctuation edits in .gitattributes and keep the header
  comment and docstring first in compare/vote.js and
  test_notes_dom_xss_helpers.py.

Both fixes have a node test that fails on the previous head.

* test(notes): make script rejection assertion case-insensitive

Address CodeQL js/bad-tag-filter alert #1150 in test-only assertion and refresh Notes evidence manifest checksum.

---------

Co-authored-by: Léo <leograndcontact@gmail.com>
2026-10-15 09:29:41 +01:00
Boody 9f8eae72fd Merge pull request #6691 from bitboody/better-readme
docs(readme): generalize the star history section
2026-10-15 09:13:32 +03:00
Nguyen Thanh DatandPR #6166 Reviewer c3819e3cbf fix(docker): mount the ChromaDB volume where the image actually persists (#6166)
* fix(docker): mount the ChromaDB volume where the image actually persists

chromadb/chroma runs `chroma run /config.yaml`, and that config is one line:
persist_path: "/data". The image declares no VOLUME, so everything the store
writes lives in the container's writable layer. The chromadb-data volume was
mounted at /chroma/chroma — where pre-1.0 images kept the store — so it caught
nothing and the entire vector store was destroyed on every container recreate.

Nothing errors when that happens. The collection survives with a count of 0, so
retrieval simply returns nothing from then on, which reads as "no match".

docs/backup-restore.md tells users to archive the chromadb-data volume, which
means the documented backup was empty too.

Fixed in all three compose files. The volume was never written to, so there is
nothing to migrate.

* fix(tests,docs): harden volume-path test helper and document upgrade migration

tests/test_chromadb_volume_path.py
- _chromadb_volumes() now normalises long-form dict volume entries
  (source/target/type map) to 'source:target' strings, preventing
  AttributeError crashes if a future Compose change uses that syntax.
- test_chromadb_does_not_use_the_pre_1_0_path now uses split(':')[1]
  comparison instead of endswith(), so mount-option suffixes (:z, :ro)
  cannot mask a wrong legacy target path.
- Three new unit tests validate the helper against both YAML syntaxes
  and the mount-option edge case explicitly.

docs/chromadb-volume-migration.md (new)
- Step-by-step guide for users upgrading from pre-#6166 Docker installs
  whose ChromaDB data accumulated in the container's writable layer.
- Covers: detecting the situation, backing up via 'docker cp', seeding
  the named volume before recreating the container, verification, and
  rollback. Validated with disposable Docker volumes.
- Distinguishes fresh installs (no action needed) from existing
  installs with live writable-layer data (action needed before recreate).

docs/backup-restore.md
- Extended ChromaDB caveat block to cross-reference the new migration
  guide for users upgrading from pre-#6166.

Closes the P1 documentation gap and P2/P3 test-robustness findings
from the PR #6166 adversarial review.

* fix(docs,tests): eliminate ChromaDB migration data-loss risks and enforce safe cutover

- Require service quiescence before cold database copy to prevent torn SQLite pages
- Mandate container preservation via immutable Docker image commit before recreation
- Enforce positive empty check on destination volume prior to seeding
- Add staging container validation on an isolated loopback port before Compose cutover
- Provide verified rollback procedures prohibiting return to legacy /chroma/chroma mount
- Add regression test coverage for all migration safety invariants

---------

Co-authored-by: PR #6166 Reviewer <reviewer@odysseus-review.local>
2026-10-14 12:20:35 +01:00
6fceb6ccd3 fix(security): deny generated-image access when ownership verification fails (#6268)
* fix(security): deny generated-image access when ownership verification fails

The except Exception block in serve_generated_image catches all
exceptions during ownership verification and falls through to serve
the file anyway. If the database is down or corrupted, the ownership
check is bypassed entirely — any authenticated user can download any
generated image by guessing the content-hash filename.

Raise HTTP 503 (Service Unavailable) instead of falling through,
so the endpoint fails closed when verification is impossible. This
matches the defense-in-depth principle: deny access on verification
errors rather than granting it.

* fix(security): enforce fail-closed ownership and secure caching for generated images

- Fail closed on missing gallery records, null/empty owners, and DB errors
- Support both cookie session and bearer API token owners via effective_user
- Add in-memory registry for freshly generated images to preserve access
- Eliminate file existence oracle by verifying ownership before disk probing
- Update Cache-Control to private, no-cache, must-revalidate
- Pass owner attribution through tool execution and image MCP server
- Add comprehensive hermetic regression tests for ownership gates and caching

* fix(security): sanitize tool owner arguments and drop unneeded MCP env fallback

- Remove redundant and unsafe ODYSSEUS_MCP_IMAGE_OWNER fallback in image_gen_server.py to fix 4 tests in test_env_reference.py.
- Sanitize caller-supplied tool arguments across all MCP and email tool dispatch paths in src/tool_execution.py: strip untrusted _odysseus_* keys from arguments.
- Only inject _odysseus_owner when verified trusted server context is present, preventing untrusted/anonymous users from spoofing ownership claims.
- Sanitize empty/whitespace owner strings in image_gen_server.py to None.
- Add comprehensive regression tests in test_generated_image_ownership.py for argument sanitization, owner injection, fallback propagation, and server sanitization.

---------

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
Co-authored-by: PR #6166 Reviewer <reviewer@odysseus-review.local>
2026-10-14 12:18:50 +01:00
Robert Vind-GardoșandPR #6166 Reviewer 501059805f fix(cleanup): preserve transcripts with stale message counts (#6610)
* fix(cleanup): preserve transcripts with stale message counts

* fix(cleanup): accurately attribute freed space and bound recent session query

* fix(cleanup): add portable fallback for SQLite runtimes lacking RETURNING

---------

Co-authored-by: PR #6166 Reviewer <reviewer@odysseus-review.local>
2026-10-14 11:21:53 +01:00
353ea00736 fix(auth): honor AUTH_ENABLED=false in admin-gated app-config routes (#6029)
* fix(auth): honor AUTH_ENABLED=false in admin-gated app-config routes

With auth explicitly disabled (reverse-proxy deployments) there is no
session user, so the inline admin checks in auth_routes.py returned 403
unconditionally and settings changes were silently lost. The central
require_admin in core/middleware.py already allows this case; the inline
checks did not.

- add _require_admin_user helper mirroring require_admin semantics and
  use it in the app-config routes (settings, features, integrations)
- return unscrubbed settings on GET /settings when auth is disabled
  (the caller is the operator)
- settings.js: check res.ok in saveDefault so a failed save no longer
  reports 'Saved'
- add regression tests

User-management routes keep requiring a real admin identity; they act on
the user store, which is not meaningful with auth disabled.

Fixes #6028

* fix(settings): verify response.ok on save and expand auth regression tests

- Ensure all settings save handlers in settings.js check response.ok before displaying success notifications, preventing false 'Saved' messages on server rejection.
- Add DOM and JS unit tests verifying response.ok checks and error handling across settings handlers.
- Expand tests/test_admin_routes_auth_disabled.py with comprehensive authorization test coverage for AUTH_ENABLED=false and AUTH_ENABLED=true across settings, features, integrations, secret scrubbing, and user management.

---------

Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
Co-authored-by: PR #6029 Reviewer <reviewer@odysseus-review.local>
2026-10-14 09:47:57 +01:00
Robert Vind-GardoșandPR #6166 Reviewer 0c56527d12 fix(email): preserve mail when bulk Trash moves fail (#6633)
* fix(email): preserve mail when bulk Trash moves fail

* fix(email): selective UID EXPUNGE and safe bulk delete cache invalidation

* fix(email): eliminate mailbox-wide EXPUNGE TOCTOU race

- Strictly prohibit mailbox-wide EXPUNGE in bulk email deletion fallback
- Restrict cleanup exclusively to selective RFC 4315 UID EXPUNGE <set>
- Track and preserve pre-existing \Deleted flags if selective expunge fails
- Retain local index records and preserve source emails when cleanup fails
- Ensure consistent partial-failure error semantics across all failure modes
- Add comprehensive hermetic tests for concurrent clients, missing UIDPLUS,
  disconnects after COPY/STORE/EXPUNGE, and retry safety

---------

Co-authored-by: PR #6166 Reviewer <reviewer@odysseus-review.local>
2026-10-14 09:01:42 +01:00
Robert Vind-GardoșandAlexandre Teixeira c23b1be3f8 fix(history): reject implicit and coerced truncation targets (#6565)
* fix(history): reject implicit and coerced truncation targets

* fix(history): reject falsy non-string message IDs; drop redundant keep_count guard

The or-chain used to resolve before_msg_id / message_id evaluated
falsy non-strings (False, 0) to '' before the isinstance(…, str) check
was reached, so they silently bypassed type validation.  Replace the
chain with explicit presence-aware logic that falls through on None or
empty string (preserving alias semantics) but rejects any other
non-string value with HTTP 400.

Also remove the now-tautological 'if keep_count >= 0:' guard, which
is always True after the negativity check introduced in the parent
commit.  The DB block is unconditional and indented accordingly.

Tests: add {'before_msg_id': False}, {'before_msg_id': 0},
{'message_id': 0} to the parametrised rejection suite.

36 passed, 0 failed (Python 3.14.4 / pytest 9.1.1).

---------

Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-10-14 08:41:38 +01:00
zai184andAlexandre Teixeira 86b886c611 feat(skills): remote-only tag hides skills from local endpoints (#6693)
Skills tagged remote-only in frontmatter are excluded from the injected
skill index when the active model's endpoint is local (loopback/private/
tailscale per is_local_endpoint). Big on-demand reference lookups
overwhelm small local contexts; local models never see the skill, while
remote models and API/UI listings are unaffected.

- SkillsManager.index_for gains optional keyword-only local_model flag
  (None = don't gate, same contract as active_toolsets=None)
- _build_system_prompt/_build_base_prompt thread endpoint_url from
  _build_route_request_state; unknown endpoint fails open
- tests: cover hidden-on-local, visible-on-remote/unknown, untagged
  skills never gated

Refs: discussed for the local-model overwhelm problem

Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-10-13 23:15:21 +01:00
Alexandre Teixeira f902be18f7 fix(ci): restore dev pytest baseline (#6704)
* chore(ci): initialize dev pytest baseline repair

* fix(ci): restore utility compaction tests and CSS snapshot
2026-10-13 22:11:23 +01:00
Alexandre Teixeira 1cc56cb9d7 refactor(frontend): establish source ownership and architecture gates (#6701) 2026-10-13 21:03:48 +01:00
Harshit Ojha b5b76fe46d fix(skills): inject published skills when Auto-approve is off (#6643)
With Auto-approve OFF the agent loop asked get_relevant_skills for
min_confidence=2.0, meant as 'published only'. The gate applies the
confidence check to published skills too, and confidence is 0-1, so no
user skill was ever injected, published or not. The explicit-activation
path already treats OFF as status == published.

Add a published_only flag to get_relevant_skills and pass it from both
callers that used the sentinel (relevance injection and the skill
preflight). Auto-approve ON is unchanged: a skill still needs a passing
audit and the confidence threshold.

Fixes #6634
2026-10-13 21:02:23 +01:00