Skip to content

Fix CSP eval and analytics violations#5008

Draft
ncarazon wants to merge 1 commit into
mainfrom
fix/csp-violation-by-eval
Draft

Fix CSP eval and analytics violations#5008
ncarazon wants to merge 1 commit into
mainfrom
fix/csp-violation-by-eval

Conversation

@ncarazon

@ncarazon ncarazon commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes CSP Report-Only violations found after the rollout: Google Analytics was reporting blocked beacon requests, and forecast table-to-slider conversion was triggering unsafe-eval through numeric.uncmin.

Implemented changes:

  • utils/csp.ts: expanded connect-src to allow confirmed Google Analytics collection endpoints, including regional *.google-analytics.com and www.google.com beacon URLs.
  • utils/forecasts/switch_forecast_type.ts: replaced numeric.uncmin with an in-house bounded search for converting table quantiles into slider distribution parameters, removing the eval-based dependency path.
  • utils/forecasts/__tests__/switch_forecast_type.test.ts: added coverage for table-to-slider conversion across balanced, clustered, skewed, and wide-uncertainty quantile inputs.
  • package.json / bun.lock: removed the unused numeric dependency after replacing the only runtime usage, so it can no longer be bundled and trigger eval-based CSP reports.

Note: This PR fixes some of the most noisy alerts. Other CSP violations will be fixed on the following PRs.

Summary by CodeRabbit

  • Improvements

    • Improved forecast slider generation to produce more accurate and consistently ordered quartile values across a wider range of inputs.
    • Enhanced compatibility with Google Analytics connections by allowing additional required endpoints.
  • Bug Fixes

    • Reduced the risk of invalid or incorrectly ordered slider ranges when converting forecast quantiles.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the PR’s main focus on CSP and analytics-related violations.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/csp-violation-by-eval

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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.

🧹 Nitpick comments (2)
front_end/src/utils/forecasts/__tests__/switch_forecast_type.test.ts (1)

84-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: the wide maxError tolerances weaken regression sensitivity.

For the skewed and wide-uncertainty rows, maxError of 0.10.25 means the median/quartiles may drift by up to 25% of CDF space and still pass. This reflects the bounded slider range's fit limitations, but it also lets meaningful accuracy regressions slip through. If tighter fits are achievable, consider snugging these tolerances or adding an assertion on the total scored error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@front_end/src/utils/forecasts/__tests__/switch_forecast_type.test.ts` around
lines 84 - 104, Improve regression sensitivity in the parameterized “returns a
valid slider distribution near the input quartiles” test by tightening the
0.1–0.25 maxError values for skewed and wide-uncertainty cases where feasible,
and add an assertion on aggregate quartile error if individual tolerances must
remain broad. Keep the assertions aligned with the bounded-range behavior of
convertToSliderQuartiles.
front_end/src/utils/forecasts/switch_forecast_type.ts (1)

106-125: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Optional: bound the synchronous cost of the search.

Each SEARCH_RADII pass evaluates 5^3 = 125 candidates, so this runs scoreSliderParams ~625 times, and every call rebuilds a CDF over inbound_outcome_count points via getUserContinuousQuartiles. This executes synchronously on the interaction thread when the user switches to slider mode. If inbound_outcome_count can be large in production, consider early-exit once the score is within tolerance, or memoizing per candidate, to avoid UI jank.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@front_end/src/utils/forecasts/switch_forecast_type.ts` around lines 106 -
125, Bound the synchronous optimization cost in the slider-search logic around
SEARCH_RADII and scoreSliderParams: add a suitable score-tolerance early exit
and/or memoize scores for repeated candidates, while preserving the existing
best-candidate behavior. Ensure the search cannot cause noticeable UI blocking
when inbound_outcome_count is large.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@front_end/src/utils/forecasts/__tests__/switch_forecast_type.test.ts`:
- Around line 84-104: Improve regression sensitivity in the parameterized
“returns a valid slider distribution near the input quartiles” test by
tightening the 0.1–0.25 maxError values for skewed and wide-uncertainty cases
where feasible, and add an assertion on aggregate quartile error if individual
tolerances must remain broad. Keep the assertions aligned with the bounded-range
behavior of convertToSliderQuartiles.

In `@front_end/src/utils/forecasts/switch_forecast_type.ts`:
- Around line 106-125: Bound the synchronous optimization cost in the
slider-search logic around SEARCH_RADII and scoreSliderParams: add a suitable
score-tolerance early exit and/or memoize scores for repeated candidates, while
preserving the existing best-candidate behavior. Ensure the search cannot cause
noticeable UI blocking when inbound_outcome_count is large.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae7c74b5-bf41-489d-a11e-653ce9f60141

📥 Commits

Reviewing files that changed from the base of the PR and between 6f83d3d and 16b8002.

⛔ Files ignored due to path filters (1)
  • front_end/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • front_end/package.json
  • front_end/src/utils/csp.ts
  • front_end/src/utils/forecasts/__tests__/switch_forecast_type.test.ts
  • front_end/src/utils/forecasts/switch_forecast_type.ts
💤 Files with no reviewable changes (1)
  • front_end/package.json

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-5008-fix-csp-violation-by-eval-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:fix-csp-violation-by-eval-16b8002
🗄️ PostgreSQL NeonDB branch preview/pr-5008-fix-csp-violation-by-eval
Redis Fly Redis mtc-redis-pr-5008-fix-csp-violation-by-eval

Details

  • Commit: ea91b3691e302d1334fd62f7ca40b2486f4e309d
  • Branch: fix/csp-violation-by-eval
  • Fly App: metaculus-pr-5008-fix-csp-violation-by-eval

ℹ️ Preview Environment Info

Isolation:

  • PostgreSQL and Redis are fully isolated from production
  • Each PR gets its own database branch and Redis instance
  • Changes pushed to this PR will trigger a new deployment

Limitations:

  • Background workers and cron jobs are not deployed in preview environments
  • If you need to test background jobs, use Heroku staging environments

Cleanup:

  • This preview will be automatically destroyed when the PR is closed

@ncarazon ncarazon marked this pull request as ready for review July 10, 2026 11:13
};
let bestScore = scoreSliderParams(best, question, q1, q2, q3);

for (const radius of SEARCH_RADII) {

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.

Could we add an open-bound case here and tighten the search before merging? On a both-open 0–100 question with quartiles 5/65/95, this converts back to 14.14/52.20/99.43. The old optimizer came back at 6.86/60.66/99.21, so switching input modes can now move a valid forecast quite a lot. This feels risky for a core forecasting interaction.

center: clamp01(best.center + centerOffset),
right: clamp01(best.right + rightOffset),
};
const score = scoreSliderParams(candidate, question, q1, q2, q3);

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.

This search is also seems fairly expensive for something that runs synchronously in the forecast UI. It scores 626 candidates, and each score rebuilds and standardizes the full CDF. Did we test the impact on UI and see any problems especially on group questions?

@ncarazon ncarazon marked this pull request as draft July 10, 2026 15:50
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.

2 participants