[UPSTREAM CHANGES] latest changes as of Mon Apr 27 2026 00:59:58 GMT+0000 (Coordinated Universal Time) - #226
Open
github-actions[bot] wants to merge 5457 commits into
Open
[UPSTREAM CHANGES] latest changes as of
Mon Apr 27 2026 00:59:58 GMT+0000 (Coordinated Universal Time)#226github-actions[bot] wants to merge 5457 commits into
github-actions[bot] wants to merge 5457 commits into
Conversation
Adds a reproducible benchmark suite that measures web server memory growth under high concurrency with artificial DB latency. Supports ingest-only and mixed workload (ingest + API reads + uptime checks) modes. Uses Docker Compose with tc netem for network simulation and cgroup memory sampling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore(deps): update dependency duckdb to v1.5.1 See merge request glitchtip/glitchtip-backend!2228
chore(deps): update dependency boto3 to v1.42.74 See merge request glitchtip/glitchtip-backend!2227
chore(deps): update dependency symbolic to v12.17.3 See merge request glitchtip/glitchtip-backend!2229
Add MALLOC_MMAP_THRESHOLD_=65536 and MALLOC_TRIM_THRESHOLD_=65536 to tune-malloc.sh. Forces allocations >64KB to use mmap/munmap directly instead of arena sub-allocation, so pages are returned to the OS immediately on free. Benchmarked effect: baseline RSS dropped from 483MB to 223MB (-260MB) with no throughput impact. Growth rate under load was unchanged, confirming the savings come from reduced arena fragmentation. Production analysis (VictoriaMetrics, /proc/9/maps) showed 471MB of anonymous mmap regions held by glibc arenas — 58% of RSS. The lower mmap threshold prevents large transient allocations (JSON buffers, DB result sets, pydantic model trees) from fragmenting these arenas. Also adds memray ASGI wrapper and malloc comparison benchmark script for future profiling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: add memory growth benchmark with tc netem latency injection See merge request glitchtip/glitchtip-backend!2226
fix: widen uptime monitor interval for weekly heartbeats See merge request glitchtip/glitchtip-backend!2217
feat: support otel_log envelope item type for OpenTelemetry log ingestion See merge request glitchtip/glitchtip-backend!2225
This reverts merge request !2217
add previous period subscription usage endpoint See merge request glitchtip/glitchtip-backend!2186
The ON DELETE CASCADE triggers on issueevent, issuetag, and issueaggregate must scan every hash sub-partition when an Issue is deleted. At 500+ partitions this exceeds statement_timeout, causing OperationalError during maintenance cleanup. Application code in delete_issues_in_batches() already pre-deletes child rows before deleting parent Issues, making the DB-level CASCADE redundant. - Set db_constraint=False on issue FK for IssueEvent, IssueTag, IssueAggregate models - Migration drops the three constraints on existing databases using SeparateDatabaseAndState to keep Django state in sync - Raw SQL files updated to omit the constraints for new installs Prepared with AI assistance. Human review required. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: drop issue_id FK constraints on partitioned tables See merge request glitchtip/glitchtip-backend!2230
Previously, assemble_artifacts() raised AssembleArtifactsError on validation failures (bad zip, missing manifest, org/release mismatch, path traversal). This left the assemble status stuck at ASSEMBLING, causing client SDKs to retry indefinitely — observed as 1,200+ repeat errors from a single organization uploading a non-zip file. Now all error paths set ChunkFileState.ERROR with a descriptive detail message, clean up temp resources (including any File objects already created during artifact processing), and return gracefully. Bare except clauses log warnings with exc_info for diagnostics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chore(deps): update dependency boto3 to v1.42.75 See merge request glitchtip/glitchtip-backend!2233
chore(deps): update dependency sentry-sdk to v2.56.0 See merge request glitchtip/glitchtip-backend!2235
fix: set ERROR status on artifact assembly failures See merge request glitchtip/glitchtip-backend!2231
The create_release endpoint used acreate() which threw an IntegrityError when a release with the same (organization_id, version) already existed. Changed to aget_or_create to make the endpoint idempotent, matching the behavior of create_project_release. Fixes https://app.glitchtip.com/burke-software/issues/5534440 AI Disclosure: This commit was authored with the assistance of an AI agent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Code's MCP client does not yet support automatic OAuth token refresh (grant_type=refresh_token), so users had to re-authenticate every hour. Increase access token lifetime to 8 hours to last a full work session, matching GitHub's token lifetime. AI Disclosure: This commit was authored with the assistance of an AI agent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: increase MCP OAuth access token lifetime to 8 hours See merge request glitchtip/glitchtip-backend!2237
chore(deps): update dependency boto3 to v1.42.76 See merge request glitchtip/glitchtip-backend!2238
Webhook alert recipients (generic webhook, Discord, Google Chat, ntfy, Microsoft Teams, Zulip) previously accepted any URL, including loopback, RFC1918, and cloud instance-metadata addresses. Any user with alert-create permission could point a webhook at an internal service and use a delivered alert payload as an exfiltration channel or to poke unauthenticated internal APIs. Introduce a shared url_validation module with is_ip_blocked, check_url_safe (async, for runtime), and validate_public_url (sync, for schema validation). Alerts schema rejects private-IP recipient URLs at creation time so operators see a 400 up front; each send_* transport also checks at delivery time to cover DNS rebinding and config changes. Gated by a new GLITCHTIP_ALLOW_PRIVATE_IPS env var (default False), separate from GLITCHTIP_UPTIME_ALLOW_PRIVATE_IPS: an operator may want to monitor internal services without also opening webhooks as an exfiltration channel. Uptime's existing validator is unchanged in behaviour; it now imports is_ip_blocked from the shared module so there is one source of truth.
chore(deps): update dependency boto3 to v1.42.93 See merge request glitchtip/glitchtip-backend!2325
…ault `DATA_UPLOAD_MAX_MEMORY_SIZE` was set to 4294967295 with a `# TMP REMOVE THIS` note. The value existed to paper over `DecompressBodyMiddleware`, which sets `CONTENT_LENGTH` to the same 4 GB sentinel after wrapping the request stream (the true decompressed length is unknown up front). A single request could force Django to buffer up to 4 GB before any view ran — a few concurrent requests could OOM the pod. Tie the two ends together properly: - Middleware now advertises `GLITCHTIP_MAX_UNZIPPED_PAYLOAD_SIZE` as the `CONTENT_LENGTH` sentinel. The decoder already enforces that cap at read time, so the advertised length matches the real hard ceiling. - `DATA_UPLOAD_MAX_MEMORY_SIZE` default becomes `GLITCHTIP_MAX_UNZIPPED_PAYLOAD_SIZE + 1 MB`, env-overridable, so raising the unzipped cap via env automatically widens the Django check to match. - Constants reordered so the dependent default compiles cleanly. Multipart file uploads (minidumps, source-map chunks) go through `FILE_UPLOAD_MAX_MEMORY_SIZE` and spill to disk, so this limit does not need to cover them.
The envelope event path checked `isinstance(item.user, dict)` before setting `user.ip_address = client_ip`, but `WebIngestIssueEvent.user` is always an `EventUser` pydantic model or None — never a dict. The branch never fired, so payload-supplied `user.ip_address` passed through unchanged even with `scrub_ip_addresses=True` (the project / organization setting anonymizes the connection IP but does not touch payload-supplied IPs). Mirror the `/store/` and `/security/` handlers: when the connection IP is available, overwrite the payload field or construct a fresh `EventUser`. The connection IP is already anonymized upstream in `get_ip_address()` when scrubbing is enabled, so this restores the intended privacy behavior. Adds regression tests covering both scrub states and the case where the payload does not include a `user` object. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The DNS rebinding test patches `BaseEventLoop.getaddrinfo` with a stub that must accept the same positional and keyword arguments as the real method but does not use them. Rename to the conventional `*_, **__` to satisfy `vulture --min-confidence 100`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OAuth refresh tokens and paired access tokens were previously stored in plaintext (DB column for the refresh token, cache key for the access token). A read-only snapshot of either store yielded directly usable credentials. Store only digests at rest: * ``OAuthRefreshToken.token`` and ``access_token_key`` are replaced with ``token_prefix`` (indexed, first 8 chars) + ``token_digest`` and ``access_token_digest`` (SHA-256 hex). Lookup by prefix + a constant-time digest compare. * ``_access_cache_key()`` now hashes the token string into the key, so the Valkey keyspace no longer contains access-token plaintext either. * SHA-256 is sufficient here: inputs are 256 random bits from ``generate_token()``, so a KDF adds no value. The migration truncates ``OAuthRefreshToken`` because the old columns held the only plaintext we could have rehashed. Connected OAuth clients will see their next access-token exchange fail and transparently re-authorize via the OAuth flow. Access tokens are cache-backed and expire within 8h regardless. Minor behavioural change: client-initiated revocation via ``revoke_token(RefreshToken)`` can no longer proactively purge the paired access cache entry (the digest is one-way). The cache entry expires naturally; a simultaneous ``revoke_token(AccessToken)`` from the client still purges it because the caller supplies the plaintext. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix(settings): replace 4 GB DATA_UPLOAD_MAX workaround with sized default See merge request glitchtip/glitchtip-backend!2326
fix(alerts): validate outbound webhook URLs to block SSRF See merge request glitchtip/glitchtip-backend!2324
refactor(event-ingest): apply client IP to envelope events consistently See merge request glitchtip/glitchtip-backend!2328
chore(deps): update dependency boto3 to v1.42.94 See merge request glitchtip/glitchtip-backend!2331
chore(deps): update dependency symbolic to v12.18.3 See merge request glitchtip/glitchtip-backend!2332
…faults Two related hardening changes that preserve out-of-the-box deployment behaviour across k8s, reverse-proxied, and single-host topologies: 1. SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE default based on GLITCHTIP_URL.scheme. https deployments get Secure cookies with zero operator action; http deployments (local, internal LAN) still let users log in without manual config. Both remain env-overridable in either direction. 2. Startup RuntimeWarnings (stderr, not hard failures) when DEBUG=False and either SECRET_KEY is the placeholder "change_me" or ALLOWED_HOSTS is the wildcard default. Escalation to a hard boot-time check is deferred to a major release so existing self-hosters aren't broken on upgrade. ALLOWED_HOSTS must stay wildcard-by-default because real deployments need Service DNS + Ingress host + pod IP + LB healthcheck name to work without orchestration changes; similarly SECURE_SSL_REDIRECT and HSTS stay opt-in because TLS typically terminates upstream. Those move to docs rather than defaults.
Having both `glitchtip/tests.py` and `glitchtip/tests/` in the same Python package confuses unittest discovery with "'tests' module incorrectly imported" on case-sensitive filesystems. Move the deploy-defaults test classes back into the single `glitchtip/tests.py` module, renaming the local helpers to avoid colliding with any neighbours. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix(settings): derive cookie Secure flags from URL; warn on unsafe defaults See merge request glitchtip/glitchtip-backend!2327
chore(deps): update dependency boto3 to v1.42.95 See merge request glitchtip/glitchtip-backend!2334
chore(deps): update dependency granian to v2.7.4 See merge request glitchtip/glitchtip-backend!2335
The access-token cache is keyed by sha256(plaintext), and the paired refresh-token row already stores that same sha256 in access_token_digest. Reconstructing the cache key from the digest preserves the original revocation semantics without needing the plaintext: both exchange_refresh_token and revoke_token(RefreshToken) can again delete the paired cache entry immediately rather than waiting out ACCESS_TOKEN_LIFETIME. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(deps): update dependency boto3 to v1.42.96 See merge request glitchtip/glitchtip-backend!2337
chore(deps): update dependency ruff to v0.15.12 See merge request glitchtip/glitchtip-backend!2338
chore(deps): update dependency ipython to v9.13.0 See merge request glitchtip/glitchtip-backend!2339
feat(oauth): hash refresh + access tokens at rest See merge request glitchtip/glitchtip-backend!2330
… into upstream-changes-2026-04-27
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.