Release 2026.03.1#65
Conversation
Consolidate all asset search logic into build_asset_search() in services/search.py with FTS ranking on PostgreSQL and icontains fallback on SQLite. Barcode exact matches are boosted above text matches. DRY up duplicate Q() filter blocks across views, bulk service, and resolve service. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable sentry-sdk 2.54.0 with Django and Celery integrations, conditional on SENTRY_DSN env var. Add Sentry Browser SDK 9.5.0 via CDN to both the main frontend (base.html) and admin (base_site.html), conditional on SENTRY_DSN_JS. Supports self-hosted Sentry with configurable environment and trace sample rate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Notable upgrades: Django 5.2.11→5.2.12, django-unfold 0.78.1→0.83.1, anthropic 0.78.0→0.84.0, django-celery-beat 2.8.1→2.9.0, black 26.1.0→26.3.0, isort 7.0.0→8.0.1. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Release cut that updates dependencies, introduces Sentry error tracking across the app (backend + browser/admin), and switches asset searching from icontains queries to PostgreSQL full-text search to improve relevance/performance.
Changes:
- Add Sentry SDK initialization in Django settings and include Sentry browser tracing in base + admin templates.
- Replace
build_asset_text_querywithbuild_asset_search(Postgres FTS with non-Postgres fallback) and update call sites/tests. - Refresh pinned dependencies and update environment examples to include Sentry configuration.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/templates/base.html |
Adds Sentry browser SDK initialization to the main UI template. |
src/templates/admin/base_site.html |
Adds Sentry browser SDK initialization to the Django admin UI. |
src/props/settings.py |
Adds Sentry backend initialization and enables django.contrib.postgres for Postgres search utilities. |
src/props/context_processors.py |
Exposes Sentry env/DSN JS values to templates. |
src/props/celery.py |
Notes expected Sentry/Celery integration behavior. |
src/assets/views.py |
Switches asset-related views from icontains search to the new search service. |
src/assets/services/search.py |
Implements Postgres FTS search with fallback behavior. |
src/assets/services/resolve.py |
Uses the new search service for broad asset resolution. |
src/assets/services/bulk.py |
Uses the new search service for bulk/filter query building. |
src/assets/tests/test_services.py |
Adds/updates tests for the new search behavior and ranking. |
src/assets/tests/test_views.py |
Updates test docstring to reflect new search helper usage. |
requirements.in |
Adds sentry-sdk[django,celery] to top-level requirements. |
requirements.txt |
Updates pinned dependency lockfile. |
.env.example |
Documents new Sentry-related environment variables. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | ||
| release: "{{ app_version }}", | ||
| integrations: [Sentry.browserTracingIntegration()], | ||
| tracesSampleRate: 0.1, |
There was a problem hiding this comment.
Frontend Sentry tracing is hardcoded to 0.1 here, but the backend uses SENTRY_TRACES_SAMPLE_RATE from env. This can lead to mismatched sampling between frontend and backend. Consider exposing the configured sample rate to templates (via settings/context processor) and using that value here.
| tracesSampleRate: 0.1, | |
| tracesSampleRate: {{ SENTRY_TRACES_SAMPLE_RATE|default:'0.1' }}, |
| SENTRY_TRACES_SAMPLE_RATE = float( | ||
| os.environ.get("SENTRY_TRACES_SAMPLE_RATE", "0.1") | ||
| ) |
There was a problem hiding this comment.
SENTRY_TRACES_SAMPLE_RATE is parsed with float(...) at import time. If the env var is unset or set to an invalid value, Django will fail to start with a ValueError. Consider validating/parsing this more defensively (e.g., try/except with a safe default and/or startup validation like other required env vars).
| SENTRY_TRACES_SAMPLE_RATE = float( | |
| os.environ.get("SENTRY_TRACES_SAMPLE_RATE", "0.1") | |
| ) | |
| _sentry_traces_sample_rate_raw = os.environ.get("SENTRY_TRACES_SAMPLE_RATE") | |
| if _sentry_traces_sample_rate_raw is None: | |
| SENTRY_TRACES_SAMPLE_RATE = 0.1 | |
| else: | |
| try: | |
| SENTRY_TRACES_SAMPLE_RATE = float(_sentry_traces_sample_rate_raw) | |
| except (TypeError, ValueError): | |
| SENTRY_TRACES_SAMPLE_RATE = 0.1 |
| dsn: "{{ SENTRY_DSN_JS }}", | ||
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | ||
| release: "{{ app_version }}", |
There was a problem hiding this comment.
The Sentry config values are injected into JavaScript string literals without JS escaping. If any of these contain quotes or backslashes (misconfiguration, or unexpected app_version content), it can break the script and can open an XSS vector. Use the template escape filter intended for JS strings (e.g., escapejs) for dsn/environment/release values.
| dsn: "{{ SENTRY_DSN_JS }}", | |
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | |
| release: "{{ app_version }}", | |
| dsn: "{{ SENTRY_DSN_JS|escapejs }}", | |
| environment: "{{ SENTRY_ENVIRONMENT|default:'development'|escapejs }}", | |
| release: "{{ app_version|escapejs }}", |
| sentry_sdk.init( | ||
| dsn=SENTRY_DSN, | ||
| environment=SENTRY_ENVIRONMENT, | ||
| release=APP_VERSION, | ||
| traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE, | ||
| send_default_pii=True, | ||
| # Profile 100% of sampled transactions | ||
| profiles_sample_rate=1.0, |
There was a problem hiding this comment.
send_default_pii=True will send potentially sensitive user/request data (e.g., user identifiers, IPs, cookies depending on integration) to Sentry. If this isn’t explicitly intended for all deployments, consider defaulting it to False and enabling it via a dedicated env flag/documentation.
| "app_version": settings.APP_VERSION, | ||
| "SENTRY_DSN_JS": getattr(settings, "SENTRY_DSN_JS", ""), | ||
| "SENTRY_ENVIRONMENT": getattr(settings, "SENTRY_ENVIRONMENT", ""), |
There was a problem hiding this comment.
Templates currently can’t access SENTRY_TRACES_SAMPLE_RATE, so they hardcode tracesSampleRate. Consider adding the configured sample rate (and possibly a boolean enabled flag) to this context so frontend sampling can stay aligned with backend configuration.
| # Sentry error tracking (feature disabled if SENTRY_DSN not set) | ||
| # For self-hosted Sentry, use your instance's DSN | ||
| # SENTRY_DSN=https://examplePublicKey@sentry.yourdomain.com/1 | ||
| # SENTRY_DSN_JS=https://examplePublicKey@sentry.yourdomain.com/2 | ||
| # SENTRY_ENVIRONMENT=production | ||
| # SENTRY_TRACES_SAMPLE_RATE=0.1 |
There was a problem hiding this comment.
The comment says Sentry is disabled if SENTRY_DSN isn’t set, but the frontend templates are gated by SENTRY_DSN_JS. As written, you can end up with frontend-only or backend-only Sentry depending on which DSN is set. Consider clarifying the wording to reflect that SENTRY_DSN enables backend reporting and SENTRY_DSN_JS enables browser/admin reporting.
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | ||
| release: "{{ app_version }}", | ||
| integrations: [Sentry.browserTracingIntegration()], | ||
| tracesSampleRate: 0.1, |
There was a problem hiding this comment.
Frontend Sentry tracing is hardcoded to 0.1 here, but the backend uses SENTRY_TRACES_SAMPLE_RATE from env. This can lead to mismatched sampling between frontend and backend. Consider exposing the configured sample rate to templates (via settings/context processor) and using that value here.
| tracesSampleRate: 0.1, | |
| tracesSampleRate: {{ SENTRY_TRACES_SAMPLE_RATE|default:"0.1" }}, |
| dsn: "{{ SENTRY_DSN_JS }}", | ||
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | ||
| release: "{{ app_version }}", |
There was a problem hiding this comment.
The Sentry config values are injected into JavaScript string literals without JS escaping. If any of these contain quotes or backslashes, it can break the script and can open an XSS vector. Use the template escape filter intended for JS strings (e.g., escapejs) for dsn/environment/release values.
| dsn: "{{ SENTRY_DSN_JS }}", | |
| environment: "{{ SENTRY_ENVIRONMENT|default:'development' }}", | |
| release: "{{ app_version }}", | |
| dsn: "{{ SENTRY_DSN_JS|escapejs }}", | |
| environment: "{{ SENTRY_ENVIRONMENT|default:'development'|escapejs }}", | |
| release: "{{ app_version|escapejs }}", |
PostgreSQL ts_rank() returns ~1e-20 for non-matching content rather than exactly 0, so filtering on fts_rank > 0 matched everything. Switch to the @@ full-text match operator via Django's filter(search=query) for correct boolean matching. Also move tags__name out of SearchVector to avoid M2M JOIN row duplication and update .dockerignore to exclude .worktrees/ (1.5GB) and bin/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clear ANTHROPIC_API_KEY in conftest.py so eager Celery tasks don't hit the real API when ANTHROPIC_API_KEY is set in Docker .env - Fix AI memory test: use real uploaded file instead of fake path, and use image dimensions (8000x6001) that actually exceed the 48M pixel limit - Fix email branding test: use settings.SITE_NAME instead of hardcoded "PROPS" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use |escapejs filter on all JS string interpolations to prevent XSS from misconfigured DSN/environment values - Make frontend tracesSampleRate dynamic via SENTRY_TRACES_SAMPLE_RATE context variable instead of hardcoded 0.1 - Parse SENTRY_TRACES_SAMPLE_RATE defensively with try/except - Clarify settings comments re: SENTRY_DSN vs SENTRY_DSN_JS scope Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-compute tsvector on Asset model instead of building it per query. PostgreSQL trigger auto-updates the vector on name/description changes. Migration backfills existing rows and creates a GIN index for fast lookups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Commits