agnes-the-ai-analyst/src
ZdenekSrotyr 3e19caa975
fix(security): RBAC filter uses stable user_id instead of mutable email local-part (#293) (#299)
* fix(security): RBAC filter for agnes_sessions matches both email local-part and user_id

The upload API (POST /api/upload/sessions) stores session files under
user_sessions/{user_id}/ (UUID), while the session collector uses the
OS username (email local-part). The session pipeline writes the directory
name verbatim into usage_session_summary.username, so the column can
contain either value depending on the ingestion path.

The RBAC filter in build_filter_clause previously only matched the email
local-part, missing sessions uploaded via the API. The fix adds an OR
condition so non-admin users see rows where username matches either their
email local-part or their user_id.

Closes #293

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(security): RBAC filter uses stable user_id instead of mutable email local-part

Closes #293

Previous fix used OR condition matching both email local-part and user_id
in the username column. This was fragile: email changes would break
filtering. This commit introduces a dedicated user_id column populated
by the session pipeline via resolve_user_id(), and switches the RBAC
filter to use it exclusively.

Changes:
- Schema v45: add user_id column to usage_session_summary and usage_events
- UsageProcessor: accept and store user_id in both tables
- runner.py: resolve_user_id() maps directory name to users.id UUID
  (exact match for UUID dirs, email LIKE for local-part dirs)
- INTERNAL_TABLES: agnes_sessions/agnes_telemetry filter on user_id column
- build_filter_clause: simplified to WHERE user_id = '<uuid>' (no OR)
- me.py/admin_user_sessions.py: query by user_id OR username for
  backward compatibility during transition
- USAGE_PROCESSOR_VERSION bumped 2→3 to trigger reprocessing/backfill
- Tests updated: 27 pass including new email-change resilience test

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(tests): bump schema version assertions 44→45

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(docs): correct resolve_user_id docstring, add TypeError comment

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(security): address review — backward-compat OR, LIKE escaping, narrower TypeError

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(security): address code review — eliminate TypeError hack, add resolve_user_id tests

Co-Authored-By: zdenek.srotyr <zdenek.srotyr@keboola.com>

* fix(db): create user_id indexes in _v44_to_v45, not _SYSTEM_SCHEMA

_SYSTEM_SCHEMA runs before the migration ladder. On an upgrade from
v42/v43/v44, usage_events / usage_session_summary already exist without
the user_id column (CREATE TABLE IF NOT EXISTS is a no-op), so the
CREATE INDEX ... (user_id) lines in _SYSTEM_SCHEMA failed to bind and
aborted _ensure_schema — the app would not start post-upgrade. Move the
index creation to _v44_to_v45, which ADDs the column first. Same pattern
as the v41 audit_log indices.

* fix(usage): bump USAGE_PROCESSOR_VERSION 3→4 for user_id backfill

#303 shipped USAGE_PROCESSOR_VERSION=3 (release 0.54.12) for its
<command-name> slash extraction. This PR's 2→3 bump collided with it
on rebase, so the reprocess loop would not re-trigger to backfill the
new user_id column on deployments already running v3. Bump to 4.

* release: 0.54.13 — RBAC filter uses stable user_id (#293)

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-14 14:12:54 +00:00
..
observability feat(observability): optional PostHog integration (#231) 2026-05-08 17:57:10 +04:00
repositories fix(security): RBAC filter uses stable user_id instead of mutable email local-part (#293) (#299) 2026-05-14 14:12:54 +00:00
store_guardrails fix(store-guardrails): post-#290 review follow-up — purge tuple, filter chip, stale docs, lazy bundle_meta, logger.exception (#295) 2026-05-14 08:02:44 +02:00
__init__.py Extract Keboola into connectors/keboola module 2026-03-09 12:22:16 +01:00
audit_helpers.py Activity Center: audit log + telemetry + sessions + agnes_* tables (#278) 2026-05-12 22:41:19 +02:00
catalog_export.py feat(observability): request_id end-to-end + dev debug toolbar + centralized logging (#136) 2026-04-29 22:54:21 +02:00
category_icons.py Add /marketplace browse page + Model B opt-in stack composition (#230) 2026-05-08 14:22:19 +02:00
claude_md.py fix(claude_md): load default via importlib.resources — survives /app/config bind-mount 2026-05-04 06:53:47 +02:00
db.py fix(security): RBAC filter uses stable user_id instead of mutable email local-part (#293) (#299) 2026-05-14 14:12:54 +00:00
identifier_validation.py fix(security): #81 Group D — extractor-side identifier validation (squashed) (#97) 2026-04-27 21:46:17 +02:00
initial_workspace.py feat(initial-workspace): per-instance agnes init override (#292) 2026-05-13 20:35:01 +00:00
marketplace.py perf(marketplace): cache cover photos + restore Curated filter spacing (#294) 2026-05-14 10:09:32 +02:00
marketplace_asset_mirror.py Marketplace UX overhaul: rich plugin/skill/agent detail + filename rename (#251) 2026-05-12 08:38:39 +00:00
marketplace_asset_validation.py Marketplace UX overhaul: rich plugin/skill/agent detail + filename rename (#251) 2026-05-12 08:38:39 +00:00
marketplace_filter.py Marketplace UX overhaul: rich plugin/skill/agent detail + filename rename (#251) 2026-05-12 08:38:39 +00:00
marketplace_listing.py Activity Center: audit log + telemetry + sessions + agnes_* tables (#278) 2026-05-12 22:41:19 +02:00
marketplace_metadata.py Marketplace UX overhaul: rich plugin/skill/agent detail + filename rename (#251) 2026-05-12 08:38:39 +00:00
marketplace_urls.py perf(marketplace): cache cover photos + restore Curated filter spacing (#294) 2026-05-14 10:09:32 +02:00
orchestrator.py feat(observability): optional PostHog integration (#231) 2026-05-08 17:57:10 +04:00
orchestrator_security.py fix(security): #81 Group A — orchestrator attach hardening (squashed) (#95) 2026-04-27 21:34:04 +02:00
profiler.py Keboola cutover: native parquet path + sync correctness + auto-discover protection (#190) 2026-05-07 12:12:14 +02:00
rbac.py Activity Center: audit log + telemetry + sessions + agnes_* tables (#278) 2026-05-12 22:41:19 +02:00
remote_query.py fix(v2): #134 BigQuery cross-project errors return structured 502/400 + BqAccess facade (#138) 2026-04-30 10:11:20 +02:00
sanitize_news.py feat(home): state-aware /home + /setup-advanced + schema v26 (#228) 2026-05-08 18:28:47 +02:00
scheduler.py Keboola cutover: native parquet path + sync correctness + auto-discover protection (#190) 2026-05-07 12:12:14 +02:00
sql_safe.py feat(v2): claude-driven fetch primitives + 0.14.0 (#102) 2026-04-29 01:07:19 +02:00
store_categories.py feat(store): /store + /my-ai-stack — community marketplace + per-user composition 2026-05-05 02:53:49 +02:00
store_naming.py Flea-market upload guardrails + soft delete + JOIN-based admin queue (#233) 2026-05-09 17:32:53 +04:00
usage_ask.py Activity Center: audit log + telemetry + sessions + agnes_* tables (#278) 2026-05-12 22:41:19 +02:00
usage_attribution_helpers.py Activity Center: audit log + telemetry + sessions + agnes_* tables (#278) 2026-05-12 22:41:19 +02:00
welcome_template.py feat(setup): configurable instance brand + connector setup overhaul (#268) 2026-05-12 17:10:08 +02:00