Skip to content

trunk-merge/pr-107620/99443364-8fe2-496e-b447-5610198465e4 - #107626

Closed
trunk-io[bot] wants to merge 289 commits into
masterfrom
trunk-merge/pr-107620/99443364-8fe2-496e-b447-5610198465e4
Closed

trunk-io[bot] wants to merge 289 commits into
masterfrom
trunk-merge/pr-107620/99443364-8fe2-496e-b447-5610198465e4

Conversation

@trunk-io

@trunk-io trunk-io Bot commented Sep 28, 2026

Copy link
Copy Markdown
Trunk Merge Pull Request Banner

This pull request was created and is being managed by Trunk Merge.

This pull request is based on the master branch at SHA 69a4765903776a5e70d4633590673395b1eaec2f.

See more details here.

When CI completes, this pull request will be closed automatically.

Pull Requests Being Tested

This pull request is testing the changes from pull request 107620.

Dependencies

This pull request depends on the changes from pull requests 107389, 101857, 107409, 102336, 107079, and 104978.

orian and others added 30 commits September 23, 2026 08:10
hpouillot and others added 25 commits September 28, 2026 12:54
A config value and a subsection name resolve escapes differently. A value keeps the escaped
character of \" and \\; a subsection name does the same, but it also drops a backslash that
precedes anything else. Git therefore reads [remote "ori\gin"] as the remote origin and
[remote "tab\there"] as tabthere. I checked both against real Git.

The header decoder kept that backslash, so the name did not match origin and an earlier
remote, such as upstream, won the release instead. The subsection name now has its own
decoder. Two cases cover it: the name a dropped escape produces, and the remote selection
that follows from it. Both fail without the change.


Generated-By: PostHog Desktop
Task-Id: 7c27427d-8fcc-4bc7-b7a2-0946a5a9538f
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

📝 Walkthrough

Walkthrough

The pull request adds HogQL catalog traversal metadata, configurable calendar sync intervals, and AI-first workflow and email-template creation flows. It also updates sandbox request validation, MCP loop-tool filtering, Fleetio imports, template edit notifications, and the CLI release version and changelog.

Priority: ⬇️ Low

Merge Risk: 🟡 Moderate · up to 83a7f

Fleetio imports of service entry line items can fail when a service entry is deleted during a sync. Resolve that before merging. A malformed sandbox URL can also cause a server error instead of a clear rejection.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 83a7f

The new flows have meaningful security boundaries. The direct sandbox route has restrictive origin and redirect controls, but the new email preview can display saved HTML whose external-resource behavior is not fully established. Calendar configuration also depends on the administrator check applying to the same project being updated.

Retained concerns

  • Medium · security · inferred: A newly rendered saved-template preview supplies template HTML to a sandboxed srcDoc iframe. The sandbox blocks scripts and same-origin access, but does not by itself block external images or other passive resource requests. If saved HTML can contain external URLs and the effective content policy permits them, opening the preview can contact a third party before the viewer interacts with it.
Security review details

Security Blast Radius

  • inferred — The preview concern is bounded to browsers that display saved email designs containing permitted external resources; neither a wider cross-tenant exposure nor effective blocking by deployment content policy was established.

Security Findings and Attack Paths

  • inferred — A party able to place an external resource URL in saved template HTML could cause a viewer's browser to request it when the new thumbnail renders, if content policy permits the request. The iframe's script and origin isolation is strong counterevidence to script execution, not proof that passive requests are blocked.

Trust Boundaries and Controls

  • observed — The direct sandbox request is limited to the configured Hogland origin, and that transport does not follow redirects. The command path checks task/run visibility before obtaining connection credentials.
  • inferred — Calendar persistence rejects an integration outside the supplied team, but the available inspection does not settle whether user_permissions.current_team, used for the administrator check, always denotes the same team as routing-derived self.team_id.

Resilience and Maintainability Implications

  • observed — The calendar collector accounts for retry and recent-start markers, and repeated event processing uses team-scoped upsert and delete operations. A failure while persisting the failure marker itself was not established as covered.

Hardening Proposals

  • proposed — Verify the effective content policy and resource-loading behavior for saved-template previews; if passive third-party requests are unwanted, constrain iframe resource loading as well as script execution.
  • proposed — Establish explicitly that the calendar administrator check evaluates the routing-selected target team for URL-selected and token-selected requests, rather than relying on an unrelated current-team preference.
🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the Trunk Merge test setup, base commit, tested pull request, and dependencies, but it does not follow the repository template. It omits the Problem, Changes, testing details,… Replace or supplement the Trunk Merge text with a completed repository-template description. State the user-facing problem, observable changes, automated tests and untested areas, select exactly one release-status option, record changelog a…
Full details: Description check

Explanation

The description explains the Trunk Merge test setup, base commit, tested pull request, and dependencies, but it does not follow the repository template. It omits the Problem, Changes, testing details, Release status, notifications, Docs update, and Agent context sections.

Resolution

Replace or supplement the Trunk Merge text with a completed repository-template description. State the user-facing problem, observable changes, automated tests and untested areas, select exactly one release-status option, record changelog and docs decisions, and complete Agent context or remove it if no agent authored the change.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (7)
posthog/hogql/catalog_traversal.py-186-204 (1)

186-204: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Cache the None result for unserializable canonical tables.

When serialize_fields raises, _canonical_name returns None without writing to canonical_name_cache. Every later call for the same table runs the full serialization again and increments canonical_unserializable again. _resolve_chain at Line 247 can call _canonical_name once per chain step, so a single broken table can cost many repeated serializations. The repeated counts also inflate the aggregate warning.

Proposed fix
         except Exception:
             self.omissions["canonical_unserializable"] += 1
+            self.canonical_name_cache[id(target)] = None
             return None
products/customer_analytics/backend/facade/api.py-4269-4279 (1)

4269-4279: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Validate interval_minutes in the write path.

update_calendar_sync_interval stores any integer without checking it. get_calendar_sync_interval silently maps values outside ALLOWED_SYNC_INTERVALS back to 60. Any caller that bypasses the serializer can therefore persist a value that the API reports as 60, while the coordinator reads the stored value. Reject values outside ALLOWED_SYNC_INTERVALS here, or confirm that the coordinator uses get_calendar_sync_interval.

Proposed fix
     from products.customer_analytics.backend.logic.calendar_sync import (  # noqa: PLC0415
+        ALLOWED_SYNC_INTERVALS,
         SYNC_INTERVAL_CONFIG_KEY,
         update_calendar_sync_config,
     )
 
+    if interval_minutes not in ALLOWED_SYNC_INTERVALS:
+        raise ValueError("unsupported calendar sync interval")
     try:
docs/internal/hogql-language-service.md-168-168 (1)

168-168: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Hyphenate the compound adjective.

Change "feature flagged" to "feature-flagged".

Source: Linters/SAST tools

products/customer_analytics/backend/logic/calendar_sync.py-148-150 (1)

148-150: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

A failure marker can mask the original exception.

mark_calendar_sync_failed raises Integration.DoesNotExist if the integration is deleted during the sync. In that case, the new exception replaces the original error. The temporal layer then cannot classify the original error, such as CalendarSyncError or GoogleWorkspaceEgressBudgetExhausted. Catch errors from the marker so that the original exception is re-raised.

Fix
     except Exception:
-        mark_calendar_sync_failed(integration_id, team_id)
+        try:
+            mark_calendar_sync_failed(integration_id, team_id)
+        except Integration.DoesNotExist:
+            pass
         raise
products/tasks/backend/presentation/views/api.py-3469-3469 (1)

3469-3469: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Reject invalid Hogland ports instead of raising.

If connection.sandbox_url contains a nonnumeric or out-of-range port, the delegated check raises ValueError when it reads target.port. The command endpoint calls this check before its forwarding try block, so the request returns a server error instead of the intended 400. Catch invalid-port errors inside is_hogland_sandbox_url and return False. Python 3.13 documents this port behavior. (docs.python.org)

products/workflows/frontend/Workflows/newWorkflowHandoff.ts-19-19 (1)

19-19: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guard the missing project ID.

String(projectLogic.findMounted()?.values.currentProjectId) becomes "undefined" or "null" when projectLogic is unmounted or the project has not loaded. The request then goes to /api/projects/undefined/hog_flows/. That request fails, and the handoff shows the "could not be opened" toast. Return null early when the ID is missing.

Proposed fix
-    const projectId = String(projectLogic.findMounted()?.values.currentProjectId)
+    const currentProjectId = projectLogic.findMounted()?.values.currentProjectId
+    if (currentProjectId == null) {
+        return null
+    }
+    const projectId = String(currentProjectId)
products/warehouse_sources/backend/temporal/data_imports/sources/COVERAGE_GAPS_APPENDIX.md-3227-3227 (1)

3227-3227: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the Fleetio inventory when marking gaps complete.

These checked entries add five streams, but the “Today (9)” line still lists only the original nine. Change that line to “Today (14)” and include the five new stream names.

🧹 Nitpick comments (2)
products/customer_analytics/backend/presentation/views/serializers.py (1)

1488-1495: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared constant for allowed intervals.

The literal (5, 15, 30, 60) repeats ALLOWED_SYNC_INTERVALS from logic/calendar_sync.py. If the two lists diverge, the API can accept values that get_calendar_sync_interval then silently maps to 60. Presentation cannot import logic directly. Expose the tuple through the facade, then use a ChoiceField or validate against that tuple.

products/customer_analytics/backend/temporal/calendar_sync.py (1)

122-143: 🚀 Performance & Scalability | 🔵 Trivial

The coordinator loads every Google Calendar config every 5 minutes.

The collector filters in Python. Each run iterates over all google-calendar integrations and reads the complete config JSON for each one. The run frequency increased from hourly to every 5 minutes, which multiplies this full scan by 12. This load is acceptable at the current scale. As the number of integrations grows, move the due-time filter into SQL or store next_sync_at in an indexed column.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 26017d25-9452-4cfe-85d2-cd042c65f9b8

📥 Commits

Reviewing files that changed from the base of the PR and between 69a4765 and 83a7f13.

⛔ Files ignored due to path filters (4)
  • cli/Cargo.lock is excluded by !**/*.lock
  • products/customer_analytics/frontend/generated/api.schemas.ts is excluded by !**/generated/**
  • products/customer_analytics/frontend/generated/api.ts is excluded by !**/generated/**
  • products/customer_analytics/frontend/generated/api.zod.ts is excluded by !**/generated/**
📒 Files selected for processing (76)
  • cli/.sampo/changesets/event-hash-ignores-chunk-file-names.md
  • cli/.sampo/changesets/section-aware-git-config.md
  • cli/CHANGELOG.md
  • cli/Cargo.toml
  • docs/internal/hogql-language-service.md
  • frontend/src/lib/components/EmailPreviewThumbnail/EmailPreviewThumbnail.test.tsx
  • frontend/src/lib/components/EmailPreviewThumbnail/EmailPreviewThumbnail.tsx
  • frontend/src/lib/constants.tsx
  • frontend/src/scenes/max/aiFirstCreate/AiFirstCreateScene.tsx
  • frontend/src/scenes/max/aiFirstCreate/aiFirstHandoffLogic.test.ts
  • frontend/src/scenes/max/aiFirstCreate/aiFirstHandoffLogic.ts
  • frontend/src/scenes/max/aiFirstCreate/aiFirstMode.ts
  • posthog/api/services/query.py
  • posthog/api/test/test_query_service.py
  • posthog/hogql/catalog_traversal.py
  • posthog/hogql/language_service.py
  • posthog/hogql/test/test_language_service.py
  • products/customer_analytics/backend/facade/api.py
  • products/customer_analytics/backend/facade/contracts.py
  • products/customer_analytics/backend/logic/calendar_sync.py
  • products/customer_analytics/backend/presentation/views/serializers.py
  • products/customer_analytics/backend/presentation/views/views.py
  • products/customer_analytics/backend/temporal/calendar_sync.py
  • products/customer_analytics/backend/test/test_calendar_sync.py
  • products/customer_analytics/backend/test/test_views.py
  • products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/calendar/CalendarSyncConfig.tsx
  • products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/calendar/calendarSyncLogic.ts
  • products/customer_analytics/mcp/tools.yaml
  • products/messaging/backend/api/message_templates.py
  • products/messaging/backend/api/test/test_message_templates.py
  • products/posthog_ai/frontend/api/logics.ts
  • products/posthog_ai/frontend/api/tools.ts
  • products/posthog_ai/frontend/components/composer/AttachedContextBar.test.tsx
  • products/posthog_ai/frontend/components/composer/AttachedContextBar.tsx
  • products/posthog_ai/frontend/components/tool/widgets/CreateNotebookWidget.tsx
  • products/posthog_ai/frontend/components/tool/widgets/extractors.ts
  • products/posthog_ai/frontend/types/contextTypes.ts
  • products/posthog_ai/frontend/utils/getToolOutputRecord.ts
  • products/tasks/backend/facade/api.py
  • products/tasks/backend/presentation/views/api.py
  • products/tasks/backend/tests/test_api.py
  • products/tasks/backend/tests/test_sandbox_url_validation.py
  • products/tasks/mcp/tools.yaml
  • products/warehouse_sources/backend/temporal/data_imports/sources/COVERAGE_GAPS_APPENDIX.md
  • products/warehouse_sources/backend/temporal/data_imports/sources/fleetio/canonical_descriptions.py
  • products/warehouse_sources/backend/temporal/data_imports/sources/fleetio/fleetio.py
  • products/warehouse_sources/backend/temporal/data_imports/sources/fleetio/settings.py
  • products/warehouse_sources/backend/temporal/data_imports/sources/fleetio/tests/test_fleetio.py
  • products/workflows/frontend/MessagingTabActions.tsx
  • products/workflows/frontend/TemplateLibrary/MessageTemplate.tsx
  • products/workflows/frontend/TemplateLibrary/MessageTemplatesTable.tsx
  • products/workflows/frontend/TemplateLibrary/NewTemplateAgent.tsx
  • products/workflows/frontend/TemplateLibrary/TemplateStartingPointCard.tsx
  • products/workflows/frontend/TemplateLibrary/messageTemplateLogic.test.ts
  • products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts
  • products/workflows/frontend/TemplateLibrary/newTemplateAgentLogic.test.ts
  • products/workflows/frontend/TemplateLibrary/newTemplateAgentLogic.ts
  • products/workflows/frontend/TemplateLibrary/newTemplateHandoff.test.ts
  • products/workflows/frontend/TemplateLibrary/newTemplateHandoff.ts
  • products/workflows/frontend/TemplateLibrary/templateAgentContext.test.ts
  • products/workflows/frontend/TemplateLibrary/templateAgentContext.ts
  • products/workflows/frontend/Workflows/NewWorkflowAgent.tsx
  • products/workflows/frontend/Workflows/WorkflowScene.tsx
  • products/workflows/frontend/Workflows/newWorkflowAgentLogic.ts
  • products/workflows/frontend/Workflows/newWorkflowHandoff.test.ts
  • products/workflows/frontend/Workflows/newWorkflowHandoff.ts
  • products/workflows/frontend/Workflows/newWorkflowLogic.ts
  • products/workflows/frontend/Workflows/workflowAgentContext.ts
  • services/mcp/schema/generated-tool-definitions.json
  • services/mcp/schema/tool-definitions-all.json
  • services/mcp/schema/tool-definitions.json
  • services/mcp/scripts/generate-tools.ts
  • services/mcp/scripts/yaml-config-schema.ts
  • services/mcp/src/api/generated.ts
  • services/mcp/tests/unit/tool-filtering.test.ts
  • tach.toml
💤 Files with no reviewable changes (3)
  • cli/.sampo/changesets/section-aware-git-config.md
  • cli/.sampo/changesets/event-hash-ignores-chunk-file-names.md
  • products/workflows/frontend/Workflows/newWorkflowAgentLogic.ts

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 4 remain after this review.

)
@patch("products.tasks.backend.presentation.views.api.internal_requests_session")
@patch("products.tasks.backend.presentation.views.api.http_requests.post")
def test_command_to_hogland_sandbox_bypasses_egress_proxy(self, mock_post, mock_session_factory):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Annotate the new test signatures. The four new test methods omit annotations required by the Python guideline.

  • products/tasks/backend/tests/test_api.py#L14299-L14299: annotate the mock parameters and None return type.
  • products/tasks/backend/tests/test_api.py#L14326-L14326: add the None return type.
  • products/tasks/backend/tests/test_api.py#L14349-L14349: annotate the mock parameters and None return type.
  • products/tasks/backend/tests/test_sandbox_url_validation.py#L44-L44: annotate url, expected, and the None return type.

As per coding guidelines: “Annotate every signature.”

📍 Affects 2 files
  • products/tasks/backend/tests/test_api.py#L14299-L14299 (this comment)
  • products/tasks/backend/tests/test_api.py#L14326-L14326
  • products/tasks/backend/tests/test_api.py#L14349-L14349
  • products/tasks/backend/tests/test_sandbox_url_validation.py#L44-L44

Source: Coding guidelines

path_version="v2",
incremental_fields=[],
primary_keys=["service_entry_id", "id"],
fanout=DependentEndpointConfig(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Inspect the fan-out response-action contract without running repository code.
ast-grep outline products/warehouse_sources/backend/temporal/data_imports/sources/common/rest_source/fanout.py --match 'DependentEndpointConfig|build_dependent_resource'
rg -n -C 5 'child_response_actions|response_actions|status_code|404' products/warehouse_sources/backend/temporal/data_imports/sources/common/rest_source

Repository: PostHog/posthog

Length of output: 42004


Configure 404 handling for Fleetio child requests.

When Fleetio deletes a service entry after the parent list request, the child request can return 404. This fan-out does not configure child_response_actions, so the 404 is not ignored on the API-parent path and can fail the import. Configure a child action that ignores only 404 responses.

session.send.side_effect = responses
return urls

def _line_items(self, manager: mock.MagicMock, **kwargs: Any):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Annotate the new test signatures.

Add a SourceResponse return type to _line_items. Annotate the patched MockSession parameters in the three new tests. As per coding guidelines, “Annotate every signature.”

Also applies to: 325-325, 356-358, 368-368

Source: Coding guidelines

@trunk-io

trunk-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Author

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
the activity log logic humanizing insights can handle change of insight query as a query wrapped in an InsightVizNode The test failed because it could not find the specified path 'scenes.PreflightCheck.preflightLogic' in the store. Logs ↗︎
the activity log logic humanizing insights can handle change of a SQL insight query The test failed because it could not find the specified path 'scenes.PreflightCheck.preflightLogic' in the store. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@trunk-io trunk-io Bot closed this Sep 28, 2026
@trunk-io
trunk-io Bot deleted the trunk-merge/pr-107620/99443364-8fe2-496e-b447-5610198465e4 branch September 28, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.