[UPSTREAM CHANGES] latest changes as of Mon Jun 01 2026 01:19:22 GMT+0000 (Coordinated Universal Time) - #231
Open
github-actions[bot] wants to merge 5535 commits into
Open
[UPSTREAM CHANGES] latest changes as of
Mon Jun 01 2026 01:19:22 GMT+0000 (Coordinated Universal Time)#231github-actions[bot] wants to merge 5535 commits into
github-actions[bot] wants to merge 5535 commits into
Conversation
Subscription usage charts See merge request glitchtip/glitchtip-backend!2218
Two concurrent workers upserting overlapping rows in logs_logresource could lock tuples in different orders due to set iteration being non-deterministic. Sorting ensures consistent lock acquisition order. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
query_cold_parquet_files scanned all parquet files oldest-first, even for limit=1 queries like /events/latest/. For orgs with many date files this caused DuckDB OOM (244 MiB limit). Reverse iteration order (newest-first) and stop scanning once enough rows are collected, since UUIDv7 ordering guarantees older files cannot outrank results already found in newer files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The command was not populating issue_events_issueaggregate, so the issues-stats API returned empty data for sample issues. Now generates per-issue hourly aggregate counts alongside the existing project stats. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: populate IssueAggregate in make_sample_issues See merge request glitchtip/glitchtip-backend!2260
Adds orphaned task rescue, max_rescues crash loop prevention, and worker shutdown fixes for ASGI embedding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore(deps): upgrade django-vtasks 2.0.0 → 2.1.0 See merge request glitchtip/glitchtip-backend!2261
chore(deps): update dependency aiohttp to v3.13.5 See merge request glitchtip/glitchtip-backend!2262
chore(deps): update dependency boto3 to v1.42.80 See merge request glitchtip/glitchtip-backend!2263
chore(deps): update dependency orjson to v3.11.8 See merge request glitchtip/glitchtip-backend!2264
AuthenticationError("message") passes the message as the first positional
arg (status_code) to HttpError, causing Django to crash with
"HTTP status code must be an integer" when ninja's error handler passes
the string to HttpResponse(status=...).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore(deps): update dependency boto3 to v1.42.81 See merge request glitchtip/glitchtip-backend!2267
chore(deps): update dependency django-stubs to v6.0.2 See merge request glitchtip/glitchtip-backend!2268
chore(deps): update dependency locust to v2.43.4 See merge request glitchtip/glitchtip-backend!2269
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: use keyword arg for AuthenticationError to avoid string status_code See merge request glitchtip/glitchtip-backend!2266
Update dependency boto3 to v1.42.82 See merge request glitchtip/glitchtip-backend!2270
Update dependency django-allauth to v65.15.1 See merge request glitchtip/glitchtip-backend!2271
Update dependency ruff to v0.15.9 See merge request glitchtip/glitchtip-backend!2272
So contributors adding periodic tasks (cold-storage compaction, retention sweeps, etc.) don't add an external lock to keep them from running on every pod — django-vtasks already gives single-runner semantics for scheduled entries. Manual ``aenqueue()`` calls still race and need their own guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…floor
Follow-up to the hour-tiered span storage commit. Three changes:
- Recover a missing hour-rollup on the next compaction tick by re-deriving
it from the sealed raw file. Without recovery, a transient failure of
``_write_hour_rollup`` (slot saturation, transient S3) after a successful
seal silently drops that hour from every trend query until raw retention
expires. The seal itself is unchanged — recovery just fills in the gap
the next time compaction visits the date.
- Floor the DuckDB concurrency cap at 2 (was ``max(1, DUCKDB_THREADS)``).
On a 1-CPU pod the cap would otherwise be 1, and a single ``block=True``
project-delete rewrite would freeze every dashboard read for the
duration. Floor of 2 keeps reads moving in parallel with a rare blocking
deletion, at the cost of 2 × memory_limit worst case.
- Rename ``table_name`` → ``storage_prefix`` at the cold-storage boundary.
The value is a path component, not a PG identifier, and the old name was
misleading at every call site that used it for path construction
(``cleanup_all_cold_storage``, ``delete_org_cold_storage``,
``rewrite_parquet_excluding_project``, ``query_cold_parquet_files``,
``enumerate_*``). Partition-management functions in
``glitchtip/cold_storage.py`` that genuinely need a PG identifier keep
``table_name``; the rename stops at that boundary.
Tests cover rollup recovery (sealed-but-no-rollup -> next tick fills it
in) and legacy flat-chunk reads + day-roll (pre-MR ``org/{date}/chunk_*``
layout stays readable and gets folded into ``{date}.parquet`` on the
first daily roll, no standalone backfill needed). Full
``apps.performance`` + ``apps.organizations_ext`` + ``apps.projects`` +
``apps.logs`` + ``apps.issue_events`` suites pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The process-wide ``duckdb_slot()`` semaphore is what keeps a burst of concurrent reads from multiplying peak RSS, but it's acquired at the call site rather than inside ``get_duckdb_read_connection`` — three current callers do this correctly, but the contract was implicit. Spell it out so a future caller doesn't silently break the memory bound, and explain why the slot can't be folded into the getter (inner helpers reuse the connection under an already-held slot). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
perf(cold-storage): hour-tiered idempotent span storage + bounded reads See merge request glitchtip/glitchtip-backend!2360
Add support for Feishu group bot webhooks as a new alert recipient type. Feishu uses its own interactive card message format rather than the Slack-compatible format, so a dedicated sender is required. Also fix webhook tests that were failing because the SSRF guard (_is_url_allowed) was blocking external URLs during DNS resolution in the test environment. Mock the guard in setUp so all webhook tests run correctly in isolation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: add Feishu (Lark) webhook alert recipient See merge request glitchtip/glitchtip-backend!2365
django-async-backend is a recent addition and not yet released. Make it optional so an installation can run on Django's stock sync ORM while keeping all raw-SQL optimisations: the same async surface is shimmed via ``sync_to_async`` when the flag is off. The default is off. Setting ``USE_ASYNC_BACKEND=True`` restores native async cursors, ``async_atomic`` and ``AsyncQuerySet``. All conditional indirection lives in one module (``glitchtip/async_compat.py``); the rest of the codebase imports the async surface from there. To remove the layer later, delete that module and switch ~6 import sites back to ``django_async_backend.X``. Verified with the full test suites for ``apps.event_ingest``, ``apps.uptime``, ``apps.issue_events``, ``apps.performance``, ``apps.logs``, and ``glitchtip.tests`` under both modes, plus a live ASGI sanity check (ORM-backed list endpoint + event ingest + background task persistence) in both modes. This change was developed with the assistance of AI; all code was reviewed by a human before commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
refactor: make django-async-backend opt-in via USE_ASYNC_BACKEND See merge request glitchtip/glitchtip-backend!2366
Replaces the per-org Organization.license_key approach (the previous
shape of this MR) with an instance-wide configuration model, per the
discussion on !2361.
A single-row SupportLicense model holds license_key + billing_email for
the whole instance. The classmethod resolver implements the precedence
chain:
1. BILLING_ENABLED (hosted/SaaS mode) → ("", "") — no support-license
concept applies on hosted GlitchTip
2. Per-field env-wins — GLITCHTIP_LICENSE_KEY and the new
GLITCHTIP_BILLING_EMAIL env vars each override the corresponding DB
field if set; missing env values fall back to the DB row
3. Otherwise the singleton DB row
Env-wins matches every other env-controlled setting in the codebase
(no DB-overrides-env precedent anywhere). Per-field rather than
all-or-nothing so operators can mix-and-match without footguns.
Admin registration is superuser-only and only active when
BILLING_ENABLED is false (the support-license concept is meaningless
in SaaS mode). Singleton enforced via pk=1 in save() override.
Also extracts SUBSCRIPTION_ID_PATTERN to apps/stripe/validators.py so
the rewritten license-invoice endpoint can import the same regex.
… validator - Extract _merge() helper for resolved/aresolved env-wins logic (was copy-pasted across sync/async pair) - Drop IntegrityError retry in load/aload (defended against impossible race on admin-only-written singleton) - Delete validators.py + SubscriptionIdPatternTestCase (dead since !2362 closed; key is only set via env/admin, not user input) - Strip docstrings/comments that restate names or duplicate sibling-class patterns
…ion paths License is now state stored in the DB singleton, not config. Operators set their license via Django superuser admin only. Matches the licensing pattern of GitLab EE, Mattermost, and Nexus self-hosted. - Drop GLITCHTIP_LICENSE_KEY, GLITCHTIP_BILLING_EMAIL, I_PAID_FOR_GLITCHTIP env vars - Simplify SupportLicense.resolved/aresolved to BILLING_ENABLED short-circuit + DB read - Drop _merge() helper (no env to merge with) - Trim resolver tests to 3 cases
…ense_key from public schema Without this, the previous "admin-only" commit broke /api/settings/ in isolation — it removed I_PAID_FOR_GLITCHTIP and GLITCHTIP_LICENSE_KEY env vars but left get_settings still reading them, causing AttributeError. Bundles the security fix (remove license_key from public settings — David's first review) with the wiring fix so this MR is self-consistent. - get_settings derives iPaidForGlitchTip from SupportLicense.license_key (DB) - BILLING_ENABLED short-circuits to True (hosted = always paid) - Drop license_key field from SettingsOut (was leaking the operator's Stripe subscription identifier to anonymous callers) - Hoist SupportLicense import in glitchtip/tests.py - Add test_settings_does_not_expose_license_key - Add test_i_paid_for_glitchtip_reflects_support_license
…r David) Per David: "removing a deprecated feature is a BIG deal with asking permission for, making it's own MR, targeting a MAJOR release." Restore the legacy env var as a force-paid override so existing self-hosted operators who set it (to silence the donate banner without a real license) are not broken by upgrade. Deprecation to be handled in a separate MR targeting a major release. - Restore I_PAID_FOR_GLITCHTIP env in settings.py + BILLING_ENABLED branch - get_settings: short-circuit to True when env is set, before SupportLicense lookup - Add test_legacy_i_paid_env_var_still_overrides to document backward compat
…mments Continuing David's "removing a deprecated feature is a BIG deal" rule: both GLITCHTIP_LICENSE_KEY and I_PAID_FOR_GLITCHTIP env vars existed on master before this branch. Restore them verbatim (declarations + comments) so backward-compatibility is preserved for self-hosted operators using either env on master. - Restore GLITCHTIP_LICENSE_KEY env declaration and original comments - Restore master's "Legacy setting" comment on I_PAID_FOR_GLITCHTIP (drop my prose) - Restore env.bool default chain so GLITCHTIP_LICENSE_KEY env still feeds I_PAID_FOR_GLITCHTIP - api.py "or settings.I_PAID_FOR_GLITCHTIP" fallback already covers both paths - GLITCHTIP_BILLING_EMAIL stays removed (was never on master, added by this branch)
…G_ENABLED check Comment clarifies the dual-source precedence (legacy env + new singleton) and why the BILLING_ENABLED check is explicit rather than relying on the env.bool chain (TESTING-mode settings quirk causes the chain to not propagate to I_PAID_FOR_GLITCHTIP).
- api.py: trim 3-line iPaidForGlitchTip derivation comment to 1 line - tests.py: drop 3 comments that restate the test name or the assertion - test_support_license.py: drop comment that paraphrases the assertEqual above it
…er project convention Per David: "No a-prefix allowed. If it's IO it's async." Drop the sync load()/resolved() variants — they had no production callers, only internal use by tests — and rename aload→load, aresolved→resolved on the remaining async methods. Convert SupportLicense tests to async def to match the existing apps/stripe/tests/ pattern.
…leak from public settings
Removes the unauthenticated exposure of license_key (which is a Stripe
subscription ID, today equivalent to a credential for the upcoming
license-invoice PII lookup). Replaces it with an authenticated
/api/0/instance-license/ endpoint that serves the resolved
SupportLicense to any logged-in user.
- Drop `license_key: str` field from SettingsOut + remove the
corresponding entry from the get_settings handler. The unauthenticated
/api/0/settings/ no longer returns license_key.
- New GET /api/0/instance-license/ returns
{licenseKey, billingEmail, source} where source is "env"|"db"|"none".
Reads from SupportLicense.aresolved() (env-wins precedence).
- Auth: any logged-in user (not superuser-restricted). Non-admins need
the resolved signal to render the support-license-aware UI surfaces
(banner, View Invoice, Support menu).
Builds on the SupportLicense singleton introduced in the rewritten
!2361. Lands alongside or before the license-invoice endpoint
(!2362 rewrite) to close the PII-scrape vector described in David's
review of !2362.
Per spec: license_key is a server-side credential and never flows to the frontend. Future operator actions (support link, invoice link) will be purpose-built endpoints that embed the key server-side. - Drop license_key from InstanceLicenseOut schema and handler - Replace test_response_omits_license_key + test_per_field_merge_env_key_with_db_email with focused tests covering env-source, DB-source, and BILLING_ENABLED short-circuit
Admin-set license now immediately enables paid features (e.g., Manage Billing button) without requiring a restart, fulfilling the "admin or env" promise that the env-only wiring previously broke. - get_settings() reads SupportLicense.license_key from DB instead of settings.I_PAID_FOR_GLITCHTIP env - BILLING_ENABLED short-circuits to True (hosted GlitchTip = always paid) - Trim env-related InstanceLicenseTestCase decorators (env vars dropped in !2361) - Add test_i_paid_for_glitchtip_reflects_support_license to verify wiring
Comment said /api/0/settings/, actual route is /api/settings/ (NinjaAPI
mounted at api/ with @api.get("settings/") — no 0/ prefix). David's
drive-by from !2364 review.
…d on !2361) Follow-up to !2361's rename: get_instance_license now calls the renamed async method without the a-prefix.
…1/foundation-and-sub-swap' feat(api): authenticated instance-license endpoint; remove license_key from public settings See merge request glitchtip/glitchtip-backend!2364
feat(stripe): instance-wide SupportLicense singleton + env-wins resolver + admin See merge request glitchtip/glitchtip-backend!2361
Bumps symbolic from 12.18.x to 13.1.1, updating both pyproject.toml and uv.lock together so `uv sync --frozen` (CI and the Docker build) stays consistent. The major version bump originates from symbolic's internal Rust dependency updates (gimli, goblin, scroll) and added Windows ARM64 support; there are no breaking changes to the Python API GlitchTip uses (SourceMapCache, normalize_debug_id, Archive, parse_addr, ProguardMapper, SymCache). Full test suite passes locally (1071 tests). Supersedes the Renovate MR, which only bumped pyproject.toml (leaving uv.lock inconsistent) and had fallen behind master. AI-assisted change (Claude Code); human review required before merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lockfile-only bump from 2.4.0 to 2.5.0. The constraint in pyproject.toml (~=2.2) already permits it. 2.5.0 newly declares django as an explicit dependency (previously only prometheus-client), which is satisfied by the existing top-level Django dependency. Replaces the stale Renovate MR !2234, whose branch had become unmergeable against master (uv.lock conflict). Note the branch-push pipeline on that MR passed at the same SHA; only the merge-result pipeline failed, due to the conflict — not a test regression. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore(deps): update symbolic to 13.1.1 See merge request glitchtip/glitchtip-backend!2369
chore(deps): update django-prometheus to 2.5.0 See merge request glitchtip/glitchtip-backend!2370
… into upstream-changes-2026-06-01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is auto-generated by
actions/github-script.