fix(security): close Strix tenant and connector boundaries - #1123
fix(security): close Strix tenant and connector boundaries#1123seonghobae wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
This PR hardens tenant and connector security boundaries by tightening OIDC access-token validation, pinning outbound IMAP connections to validated IPs to prevent DNS rebinding, and making several cross-tenant/cross-workspace operations replay-safe and scope-safe.
Changes:
- Enforces stricter OIDC API token requirements (dedicated audience +
typ=at+jwt+ authorized-client claim). - Pins IMAP network connections to pre-validated socket destinations (prevents second DNS lookup) and adds regression tests.
- Adds replay-safe email task creation with a partial unique index + migration, runner WS per-connection response binding, and stricter org/workspace scoping for calendar/data APIs.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/operations/auth-key-management.md | Documents new OIDC access-token requirements (audience + at+jwt + client). |
| AGENTS.md | Updates agent/security guidance for OIDC API audience and token type expectations. |
| backend/core/config.py | Adds OIDC_API_AUDIENCE and validates it (including distinctness from client id). |
| backend/scripts/start_backend.py | Extends runtime validation for new OIDC env var and distinct audience. |
| backend/api/auth.py | Enforces typ=at+jwt, dedicated API audience, and azp/client_id checks. |
| backend/services/email_client.py | Introduces ValidatedImapDestination and pinned IMAP socket connection helper. |
| backend/services/imap_worker.py | Switches IMAP sync to pinned sockets and preserves TLS hostname verification/SNI. |
| backend/api/tasks.py | Makes email-derived task creation idempotent and replay-safe (DB-enforced). |
| backend/db/models.py | Adds partial unique expression index to enforce email task idempotency. |
| backend/alembic/versions/0018_email_task_idempotency.py | Migration to collapse duplicates then install unique boundary. |
| backend/api/runner_ws.py | Binds runner responses to per-connection IDs; rejects duplicate request IDs; supports revocation. |
| backend/api/runner_config.py | Revokes live runner sockets after credential rotation. |
| backend/api/calendar.py | Enforces workspace ownership when selecting/authorizing writeback sources. |
| backend/api/data.py | Adds organization scoping to document quality surface query. |
| backend/tests/test_auth_real.py | Adds coverage for OIDC token type/audience/authorized-client enforcement. |
| backend/tests/test_config.py | Adds tests for OIDC_API_AUDIENCE behavior and distinctness. |
| backend/tests/test_start_backend.py | Updates runtime settings tests to include new OIDC env var requirements. |
| backend/tests/test_email_client_pop3_imap.py | Adds DNS rebinding regression test for pinned IMAP socket connections. |
| backend/tests/test_imap_worker.py | Updates IMAP worker tests for pinned sockets and TLS hostname behavior. |
| backend/tests/live/mail_smoke_test.py | Updates live IMAP smoke path to use pinned socket + pinned client builder. |
| backend/tests/test_tasks_api.py | Adds model/index assertions and replay/idempotency tests for email task creation. |
| backend/tests/test_alembic_migrations.py | Validates new Alembic revision installs expected unique boundary. |
| backend/tests/test_runner_ws_api.py | Adds regression tests for stale disconnects, response injection, and revocation. |
| backend/tests/test_runner_config_api.py | Adds test ensuring rotate triggers live-connection revocation. |
| backend/tests/test_calendar_api.py | Adds coverage for cross-workspace writeback rejection and workspace scoping in DB queries. |
| backend/tests/test_data_api.py | Updates fake DB layer + assertions for org scoping in data quality surface. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
PR governance metadata gate update for PR governance metadata gate is waiting on current-head requirements; see the latest check for pending reasons. |
| for attempt in range(2): | ||
| tasks_by_title = await _existing_email_tasks( | ||
| db, | ||
| auth_context=auth_context, | ||
| email_id=email.id, |
| except IntegrityError as exc: | ||
| await db.rollback() | ||
| if not _is_email_task_idempotency_conflict(exc): | ||
| raise |
| op.create_index( | ||
| _INDEX_NAME, | ||
| "ticket_tasks", | ||
| [ | ||
| "user_id", | ||
| sa.text("COALESCE(organization_id, '')"), | ||
| "source_type", | ||
| "email_id", | ||
| sa.text("sha256(convert_to(task_title, 'UTF8'))"), | ||
| ], | ||
| unique=True, | ||
| postgresql_where=sa.text("source_type = 'email' AND email_id IS NOT NULL"), | ||
| if_not_exists=True, | ||
| ) |
|
Closing as permanently blocked by long-standing merge conflicts vs develop after Loop drain. Security intent must be re-opened as a focused TDD PR on current develop (do not force-merge). |
Summary
This base-branch security follow-up remediates all seven actionable Strix findings reported against PR #1114.
Migration and configuration notes
Validation