trunk-merge/pr-110700/09492e3e-7f72-4406-a312-1f11594d193d - #110853
trunk-io[bot] wants to merge 12 commits into
Conversation
…stem tables Add system.autoresearch_training_runs, system.autoresearch_iterations and system.autoresearch_models as HogQL PostgresTables with access_scope "autoresearch", team_id, and a description on every field. Add team isolation factories through the autoresearch testing facade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 36443bea-8bcc-43cb-a5d1-ad8b183eb0d0
The overview counts series per service by scanning every series-hour row of the last day. The services_by_hour projection keeps that rollup per team, hour and service, so the query can read a few small rows. ReplacingMergeTree needs deduplicate_merge_projection_mode = 'rebuild' before it accepts a projection and to keep it through merges. A settings-only ALTER changes only the replica that runs it, so that statement runs on every LOGS host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 3538a544-5668-418a-aebd-c3430d18864a
The open head used the impressed cohort, so an open from a deeplink, the desktop app or another direct link never became a training example. The head now uses the everyone cohort, and the label still counts an open from any surface within 3 days. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 3150e9d0-d077-4e0e-b755-b3da29781c73
…bles Add addon_attachments, pipeline_couplings and team_monthly_usage tables to the Heroku source. Generalize fan-out to take any parent endpoint so usage can fan out over Enterprise teams. Skip `plan`: Heroku has no plan list endpoint, and add-ons already carry billed_price and the plan name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 38158f29-8b9a-45da-89d2-76452341e736
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 38158f29-8b9a-45da-89d2-76452341e736
Adopt the repository's frozen dataclass default for the Heroku resume and endpoint configuration value objects, satisfying the developer-experience Semgrep rule.
Adopt the repository's frozen dataclass default for the Heroku resume and endpoint configuration value objects, satisfying the developer-experience Semgrep rule.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (17)📝 WalkthroughWalkthroughThe change updates metrics4_series with a services_by_hour projection and a migration to apply it. It exposes three autoresearch tables and adds test record helpers. The inbox ranking open head now includes reports without impressions. The Heroku source adds three resources and supports configurable parent fan-out and monthly usage windows. Priority: ➖ Normal Merge Risk: 🟠 High · up to Restricted autoresearch pipeline records may be visible to users denied access to those pipelines. Correct the three table mappings before merging; update the Heroku catalog summary as well. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change expands access to training metadata and external account usage data. Team filtering and sensitive-URL redaction remain in the inspected paths, and no introduced authorization bypass was established. Import ownership, final persistence, and recovery coverage remain incomplete. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
Full details: Description checkExplanation The description only documents a Trunk Merge batch and lists included pull requests. It does not explain the user-facing problem, changes, testing, release status, documentation impact, or required agent context for this repository. Resolution Replace the merge-queue boilerplate with a standalone description using the required sections: Problem, Changes, How did you test this code?, Test rationale, Release status, Automatic notifications, Docs update, and Agent context. Summarize the bundled changes, testing evidence, feature-flag status, and agent details.
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 (1)
products/warehouse_sources/backend/temporal/data_imports/sources/COVERAGE_GAPS_APPENDIX.md-4004-4004 (1)
4004-4004: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUpdate the Heroku coverage summary.
The summary at Line 3995 still lists eleven tables. These changes add three tables, so readers do not see the current catalog there. Update the count to fourteen and add
addon_attachments,pipeline_couplings, andteam_monthly_usageto that list.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 5d16a213-1914-4d9a-abae-0f7efdcf60cd
📒 Files selected for processing (28)
posthog/clickhouse/hcl/golden/dev/logs.hclposthog/clickhouse/hcl/golden/local-multi/logs.hclposthog/clickhouse/hcl/golden/local-single/all.hclposthog/clickhouse/hcl/golden/prod-eu/logs.hclposthog/clickhouse/hcl/golden/prod-us/logs.hclposthog/clickhouse/hcl/roles/logs/metrics/metrics4.hclposthog/clickhouse/hcl/sql/dev/logs.sqlposthog/clickhouse/hcl/sql/local-multi/logs.sqlposthog/clickhouse/hcl/sql/local-single/all.sqlposthog/clickhouse/hcl/sql/prod-eu/logs.sqlposthog/clickhouse/hcl/sql/prod-us/logs.sqlposthog/clickhouse/metrics/metrics4.pyposthog/clickhouse/migrations/0345_metrics4_series_services_projection.pyposthog/clickhouse/migrations/max_migration.txtposthog/clickhouse/test/__snapshots__/test_schema.ambrposthog/hogql/database/schema/system.pyposthog/hogql/database/schema/test/test_system_tables.pyposthog/hogql/database/test/__snapshots__/test_database.ambrproducts/autoresearch/backend/facade/testing.pyproducts/signals/dags/inbox_ranking/README.mdproducts/signals/dags/inbox_ranking/tests/test_training.pyproducts/signals/dags/inbox_ranking/training/heads.pyproducts/warehouse_sources/backend/temporal/data_imports/sources/COVERAGE_GAPS_APPENDIX.mdproducts/warehouse_sources/backend/temporal/data_imports/sources/heroku/canonical_descriptions.pyproducts/warehouse_sources/backend/temporal/data_imports/sources/heroku/heroku.pyproducts/warehouse_sources/backend/temporal/data_imports/sources/heroku/settings.pyproducts/warehouse_sources/backend/temporal/data_imports/sources/heroku/source.pyproducts/warehouse_sources/backend/temporal/data_imports/sources/heroku/tests/test_heroku.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 0 remain after this review.
| autoresearch_training_runs: PostgresTable = PostgresTable( | ||
| name="autoresearch_training_runs", | ||
| postgres_table_name="autoresearch_autoresearchtrainingrun", | ||
| access_scope="autoresearch", | ||
| description="Autoresearch training runs; one row per bounded agent session that searches for a better model for a pipeline.", | ||
| fields={ | ||
| "id": UUIDDatabaseField(name="id", description="Training run UUID."), | ||
| "team_id": IntegerDatabaseField(name="team_id", description="Team the training run belongs to."), | ||
| "pipeline_id": UUIDDatabaseField( | ||
| name="pipeline_id", description="Pipeline the run trains for; joins to autoresearch_pipelines.id." | ||
| ), | ||
| "task_id": UUIDDatabaseField( | ||
| name="task_id", nullable=True, description="Task that runs the agent sandbox; joins to tasks.id." | ||
| ), | ||
| "task_run_id": UUIDDatabaseField( | ||
| name="task_run_id", nullable=True, description="Task run of the agent sandbox; joins to task_runs.id." | ||
| ), | ||
| "status": StringDatabaseField(name="status", description="One of pending, running, completed, failed."), | ||
| "iteration_budget": IntegerDatabaseField( | ||
| name="iteration_budget", description="Maximum iterations the run may record." | ||
| ), | ||
| "iteration_count": IntegerDatabaseField(name="iteration_count", description="Iterations the run recorded."), | ||
| "best_holdout_score": FloatDatabaseField( | ||
| name="best_holdout_score", | ||
| nullable=True, | ||
| description="Best holdout AUC (0 to 1) of the run's iterations (NULL before the first scored iteration).", | ||
| ), | ||
| "error": StringDatabaseField(name="error", description="Failure message; blank when the run did not fail."), | ||
| "summary": StringJSONDatabaseField( | ||
| name="summary", | ||
| description="JSON summary written on completion: champion, kept iterations, dead ends, and next steps.", | ||
| ), | ||
| "started_at": DateTimeDatabaseField( | ||
| name="started_at", nullable=True, description="When the run started (NULL while pending)." | ||
| ), | ||
| "completed_at": DateTimeDatabaseField( | ||
| name="completed_at", nullable=True, description="When the run finished (NULL while it is not finished)." | ||
| ), | ||
| "created_at": DateTimeDatabaseField(name="created_at", description="When the run was created."), | ||
| }, | ||
| ) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '1020,1225p' posthog/hogql/database/schema/system.py
sed -n '3300,3320p' posthog/hogql/database/schema/system.py
sed -n '900,965p' posthog/hogql/database/schema/test/test_system_tables.pyRepository: PostHog/posthog
Length of output: 15870
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- PostgresTable and access-scope bindings ---'
rg -n --glob '*.py' 'class PostgresTable|access_scope|PostgresTable\(' posthog/hogql posthog | head -240
printf '%s\n' '--- autoresearch model declarations and team ownership ---'
rg -n --glob '*.py' 'class Autoresearch|class AutoResearch|autoresearch_autoresearch|autoresearch_training_runs|AutoresearchTrainingRun|AutoResearchTrainingRun' posthog ee products | head -240
printf '%s\n' '--- isolation test references ---'
rg -n --glob '*.py' 'SYSTEM_TABLE_FACTORIES|system table|access_scope|team_id.*filter|PostgresTable' posthog/hogql/database/schema/test posthog/hogql | head -260Repository: PostHog/posthog
Length of output: 41795
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- PostgresTable implementation ---'
sed -n '1,240p' posthog/hogql/database/postgres_table.py
printf '%s\n' '--- scoped-table validation tests ---'
sed -n '470,645p' posthog/hogql/database/test/test_postgres_table.py
printf '%s\n' '--- autoresearch models ---'
sed -n '230,330p' products/autoresearch/backend/models.py
printf '%s\n' '--- autoresearch factories and isolation test ---'
rg -n -C 12 --glob '*.py' '_create_autoresearch_(training_run|pipeline|iteration|model)|autoresearch_training_runs|test_access_scoped_system_tables_are_filtered|team_id WHERE|isolation' posthog/hogql/database/schema/test/test_system_tables.py posthog/hogql/database/schema/test/test_information_schema.pyRepository: PostHog/posthog
Length of output: 41718
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- query-time table filtering ---'
rg -n -C 18 --glob '*.py' '_print_table_ref|team_id.*filter|team_id.*equals|blocked_resource_ids_by_scope|access_control_id' posthog/hogql posthog/hogql_queries | head -360
printf '%s\n' '--- autoresearch scope and access-control registration ---'
rg -n -C 12 --glob '*.py' 'autoresearch|RESOURCE_INHERITANCE_MAP|scope_object|_object_grant_registry|_object_grant_scopes' posthog/scopes.py posthog/hogql_queries posthog/api products/autoresearch | head -360
printf '%s\n' '--- model inheritance and isolation assertions ---'
rg -n -C 20 --glob '*.py' 'class PipelineScopedModel|class AutoresearchPipeline|class AutoresearchTrainingRun|def test_system_table_is_isolated|execute_hogql_query|other_team' products/autoresearch/backend/models.py posthog/hogql/database/schema/test/test_system_tables.py | head -420Repository: PostHog/posthog
Length of output: 42169
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- ClickHouse table-reference guard ---'
rg -n -C 28 --glob '*.py' 'def _print_table_ref|def build_access_control_guard|team_id.*context.team_id|context.team_id not found' posthog/hogql/printer posthog/hogql_queries
printf '%s\n' '--- autoresearch resource registrations ---'
rg -n -C 18 --glob '*.py' 'autoresearch.*scope|scope.*autoresearch|APIScopeObject|RESOURCE_INHERITANCE_MAP|scope_object|AccessControlViewSetMixin' posthog/scopes.py posthog/hogql_queries/access_controlled_resources.py products/autoresearch posthog/api | head -420
printf '%s\n' '--- model base classes and team fields ---'
rg -n -C 18 --glob '*.py' 'class TeamScopedRootMixin|class PipelineScopedModel|team_id|TeamScoped' products/autoresearch/backend/models.py posthog/models | head -300Repository: PostHog/posthog
Length of output: 42371
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- access-control resource registry ---'
sed -n '1,260p' posthog/hogql_queries/access_controlled_resources.py
printf '%s\n' '--- autoresearch API and access-control declarations ---'
rg -n -C 20 --glob '*.py' 'Autoresearch|autoresearch|AccessControlViewSetMixin|scope_object|access_level' products/autoresearch posthog/api posthog | grep -E 'autoresearch|Autoresearch|AccessControlViewSetMixin|scope_object' | head -360
printf '%s\n' '--- changed table and comparable child-table declarations ---'
sed -n '1020,1185p' posthog/hogql/database/schema/system.py
rg -n -C 8 --glob '*.py' 'access_control_id_field=.*pipeline|access_control_id_field=.*_id' posthog/hogql/database/schema/system.py | head -220Repository: PostHog/posthog
Length of output: 41624
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- object-grant registry and autoresearch scope ---'
rg -n -C 14 --glob '*.py' 'def _object_grant_registry|def _object_grant_scopes|AutoresearchPipeline|autoresearch' posthog/hogql/database/test/test_postgres_table.py products/access_control posthog/scopes.py | head -360
printf '%s\n' '--- exact ClickHouse wrapping block ---'
sed -n '1122,1185p' posthog/hogql/printer/clickhouse.py
printf '%s\n' '--- exact isolation test ---'
sed -n '1035,1110p' posthog/hogql/database/schema/test/test_system_tables.pyRepository: PostHog/posthog
Length of output: 14736
🏁 Script executed:
#!/bin/bash
set -e
sed -n '60,145p' posthog/hogql/database/test/test_postgres_table.py
printf '%s\n' '--- exact autoresearch scope-object declarations ---'
rg -n -C 8 --glob '*.py' 'scope_object\s*=\s*["'\"']autoresearch|scope_object.*autoresearch|autoresearch.*scope_object|class .*Autoresearch' products posthog/api posthog | head -240Repository: PostHog/posthog
Length of output: 24907
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- facade object-grant table mapping ---'
sed -n '1,65p' posthog/hogql/database/test/test_postgres_table.py
printf '%s\n' '--- exact access-control guard ---'
rg -n -C 45 --glob '*.py' '^def build_access_control_guard|access_control_id|blocked_resource_ids_by_scope|allowlisted_resource_ids_by_scope' posthog/hogql/printer/access_control.py posthog/hogql/printer/clickhouse.py posthog/hogql_queries | head -320Repository: PostHog/posthog
Length of output: 24015
🏁 Script executed:
#!/bin/bash
set -e
rg -n -C 20 --glob '*.py' 'class TeamAndOrgViewSetMixin|class AccessControlViewSetMixin|scope_object' posthog/api products/access_control products/autoresearch/backend/presentation/views/views.py | head -280Repository: PostHog/posthog
Length of output: 27962
Filter training runs by their pipeline access grant.
When a user has autoresearch access but lacks access to a pipeline, the guard compares blocked resource IDs with the training run's own id. The blocked pipeline ID does not match, so the query can return runs for that pipeline. Set access_control_id_field to pipeline_id.
Suggested fix
postgres_table_name="autoresearch_autoresearchtrainingrun",
access_scope="autoresearch",
+ access_control_id_field="pipeline_id",
description="Autoresearch training runs; one row per bounded agent session that searches for a better model for a pipeline.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| autoresearch_training_runs: PostgresTable = PostgresTable( | |
| name="autoresearch_training_runs", | |
| postgres_table_name="autoresearch_autoresearchtrainingrun", | |
| access_scope="autoresearch", | |
| description="Autoresearch training runs; one row per bounded agent session that searches for a better model for a pipeline.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Training run UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the training run belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline the run trains for; joins to autoresearch_pipelines.id." | |
| ), | |
| "task_id": UUIDDatabaseField( | |
| name="task_id", nullable=True, description="Task that runs the agent sandbox; joins to tasks.id." | |
| ), | |
| "task_run_id": UUIDDatabaseField( | |
| name="task_run_id", nullable=True, description="Task run of the agent sandbox; joins to task_runs.id." | |
| ), | |
| "status": StringDatabaseField(name="status", description="One of pending, running, completed, failed."), | |
| "iteration_budget": IntegerDatabaseField( | |
| name="iteration_budget", description="Maximum iterations the run may record." | |
| ), | |
| "iteration_count": IntegerDatabaseField(name="iteration_count", description="Iterations the run recorded."), | |
| "best_holdout_score": FloatDatabaseField( | |
| name="best_holdout_score", | |
| nullable=True, | |
| description="Best holdout AUC (0 to 1) of the run's iterations (NULL before the first scored iteration).", | |
| ), | |
| "error": StringDatabaseField(name="error", description="Failure message; blank when the run did not fail."), | |
| "summary": StringJSONDatabaseField( | |
| name="summary", | |
| description="JSON summary written on completion: champion, kept iterations, dead ends, and next steps.", | |
| ), | |
| "started_at": DateTimeDatabaseField( | |
| name="started_at", nullable=True, description="When the run started (NULL while pending)." | |
| ), | |
| "completed_at": DateTimeDatabaseField( | |
| name="completed_at", nullable=True, description="When the run finished (NULL while it is not finished)." | |
| ), | |
| "created_at": DateTimeDatabaseField(name="created_at", description="When the run was created."), | |
| }, | |
| ) | |
| autoresearch_training_runs: PostgresTable = PostgresTable( | |
| name="autoresearch_training_runs", | |
| postgres_table_name="autoresearch_autoresearchtrainingrun", | |
| access_scope="autoresearch", | |
| access_control_id_field="pipeline_id", | |
| description="Autoresearch training runs; one row per bounded agent session that searches for a better model for a pipeline.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Training run UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the training run belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline the run trains for; joins to autoresearch_pipelines.id." | |
| ), | |
| "task_id": UUIDDatabaseField( | |
| name="task_id", nullable=True, description="Task that runs the agent sandbox; joins to tasks.id." | |
| ), | |
| "task_run_id": UUIDDatabaseField( | |
| name="task_run_id", nullable=True, description="Task run of the agent sandbox; joins to task_runs.id." | |
| ), | |
| "status": StringDatabaseField(name="status", description="One of pending, running, completed, failed."), | |
| "iteration_budget": IntegerDatabaseField( | |
| name="iteration_budget", description="Maximum iterations the run may record." | |
| ), | |
| "iteration_count": IntegerDatabaseField(name="iteration_count", description="Iterations the run recorded."), | |
| "best_holdout_score": FloatDatabaseField( | |
| name="best_holdout_score", | |
| nullable=True, | |
| description="Best holdout AUC (0 to 1) of the run's iterations (NULL before the first scored iteration).", | |
| ), | |
| "error": StringDatabaseField(name="error", description="Failure message; blank when the run did not fail."), | |
| "summary": StringJSONDatabaseField( | |
| name="summary", | |
| description="JSON summary written on completion: champion, kept iterations, dead ends, and next steps.", | |
| ), | |
| "started_at": DateTimeDatabaseField( | |
| name="started_at", nullable=True, description="When the run started (NULL while pending)." | |
| ), | |
| "completed_at": DateTimeDatabaseField( | |
| name="completed_at", nullable=True, description="When the run finished (NULL while it is not finished)." | |
| ), | |
| "created_at": DateTimeDatabaseField(name="created_at", description="When the run was created."), | |
| }, | |
| ) |
| autoresearch_iterations: PostgresTable = PostgresTable( | ||
| name="autoresearch_iterations", | ||
| postgres_table_name="autoresearch_autoresearchiteration", | ||
| access_scope="autoresearch", | ||
| description="Autoresearch iterations; one row per model attempt inside a training run.", | ||
| fields={ | ||
| "id": UUIDDatabaseField(name="id", description="Iteration UUID."), | ||
| "team_id": IntegerDatabaseField(name="team_id", description="Team the iteration belongs to."), | ||
| "pipeline_id": UUIDDatabaseField( | ||
| name="pipeline_id", description="Pipeline of the iteration; joins to autoresearch_pipelines.id." |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Map iteration access control to pipeline_id.
autoresearch_iterations omits access_control_id_field, so its autoresearch guard compares the iteration id with denied pipeline IDs. A same-team iteration can therefore pass the team_id filter and be returned even when its pipeline_id is denied. Add the mapping to this declaration independently of the training-run table.
Suggested fix
access_scope="autoresearch",
+ access_control_id_field="pipeline_id",
description="Autoresearch iterations; one row per model attempt inside a training run.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| autoresearch_iterations: PostgresTable = PostgresTable( | |
| name="autoresearch_iterations", | |
| postgres_table_name="autoresearch_autoresearchiteration", | |
| access_scope="autoresearch", | |
| description="Autoresearch iterations; one row per model attempt inside a training run.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Iteration UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the iteration belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline of the iteration; joins to autoresearch_pipelines.id." | |
| autoresearch_iterations: PostgresTable = PostgresTable( | |
| name="autoresearch_iterations", | |
| postgres_table_name="autoresearch_autoresearchiteration", | |
| access_scope="autoresearch", | |
| access_control_id_field="pipeline_id", | |
| description="Autoresearch iterations; one row per model attempt inside a training run.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Iteration UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the iteration belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline of the iteration; joins to autoresearch_pipelines.id." |
| autoresearch_models: PostgresTable = PostgresTable( | ||
| name="autoresearch_models", | ||
| postgres_table_name="autoresearch_autoresearchmodel", | ||
| access_scope="autoresearch", | ||
| description="Autoresearch models; one row per trained model of a pipeline, with role champion, challenger, or archived.", | ||
| fields={ | ||
| "id": UUIDDatabaseField(name="id", description="Model UUID."), | ||
| "team_id": IntegerDatabaseField(name="team_id", description="Team the model belongs to."), | ||
| "pipeline_id": UUIDDatabaseField( | ||
| name="pipeline_id", description="Pipeline of the model; joins to autoresearch_pipelines.id." |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Map autoresearch models to pipeline_id for access control.
autoresearch_models omits access_control_id_field, so its autoresearch deny guard compares the model's id with denied pipeline IDs. The existing team_id filter does not prevent a same-team model from being returned. Set the mapping independently on this table.
Suggested fix
postgres_table_name="autoresearch_autoresearchmodel",
access_scope="autoresearch",
+ access_control_id_field="pipeline_id",
description="Autoresearch models; one row per trained model of a pipeline, with role champion, challenger, or archived.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| autoresearch_models: PostgresTable = PostgresTable( | |
| name="autoresearch_models", | |
| postgres_table_name="autoresearch_autoresearchmodel", | |
| access_scope="autoresearch", | |
| description="Autoresearch models; one row per trained model of a pipeline, with role champion, challenger, or archived.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Model UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the model belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline of the model; joins to autoresearch_pipelines.id." | |
| autoresearch_models: PostgresTable = PostgresTable( | |
| name="autoresearch_models", | |
| postgres_table_name="autoresearch_autoresearchmodel", | |
| access_scope="autoresearch", | |
| access_control_id_field="pipeline_id", | |
| description="Autoresearch models; one row per trained model of a pipeline, with role champion, challenger, or archived.", | |
| fields={ | |
| "id": UUIDDatabaseField(name="id", description="Model UUID."), | |
| "team_id": IntegerDatabaseField(name="team_id", description="Team the model belongs to."), | |
| "pipeline_id": UUIDDatabaseField( | |
| name="pipeline_id", description="Pipeline of the model; joins to autoresearch_pipelines.id." |
|
This pull request was created and is being managed by Trunk Merge.
This pull request is based on the master branch at SHA e6b3dfe3fa152fd136497b749e3287220b23368f.
See more details about each PR in the batch here:
When CI completes, this pull request will be closed automatically.
Pull Requests Being Tested
This pull request is testing a batch with the changes from pull requests 110700, 110666, 110732, and 110409 - batching documentation.