[pull] master from getsentry:master#1843
Merged
Merged
Conversation
) Propagates attachment `retention_days` from the ingest consumer to all places where attachments are written to objectstore. If Relay does not provide retention days yet, it defaults to the global retention setting or 30 days if unset, which matches the current behavior. It is expected that Relay populates the retention setting. In order to reduce load on the ingest consumer, we're not reading event retention for every message when constructing `CachedAttachment`, and instead fall back to the global default. --------- Co-authored-by: Claude <noreply@anthropic.com>
…access (#109781) Allow projects to see console-restricted symbol sources in Built-in Repositories when the organization has console platform access. This lets e.g. a Unity project add the Nintendo symbol source if the org has nintendo-switch access. When console access is revoked, a Celery task removes the corresponding symbol sources from all projects in the organization. --- Also updates `BuiltinSymbolSourcesEndpoint` to no longer be accessible as an endpoint without having Organization auth by changing the class it inherits from to `OrganizationEndpoint`. --------- Co-authored-by: Claude <noreply@anthropic.com>
…dle negative costs (#111986)
Empty file patches are generated to overwrite previous file patches. These are rendered as empty changes. We only want to preserve the last file patch for a file and we need to ensure it is a non empty file patch.
SSIA Current impl does `sync_to_async` of `async_to_sync` when ASGI is enabled. This fixes that.
…es (#111978) Display the triggered condition details on the issue detail page for `preprod_size_analysis` issues. New self-gating `SizeAnalysisTriggeredSection` component renders an `InterimSection` with a `KeyValueList` showing: - **Threshold Type** — absolute size, absolute diff, or relative diff - **Measurement** — platform-aware label derived from `head.artifact_type` event tag (e.g., "Install Size" for Apple, "Uncompressed Size" for Android) - **Query** — shown when a filter query is configured - **Condition** — human-readable threshold description (e.g., "Above 1 MB") - **Evaluated Value** — formatted with 2 decimal places and appropriate units Action buttons: - **Open Build** — always shown, links to the head build detail page - **Open Comparison** — shown for `absolute_diff` / `relative_diff` threshold types when a base artifact exists Also adds `getMetricLabelForArtifactType` to the preprod types utils, exports `formatComparisonValue` and `getConditionDescription` from mobileBuild/detect.tsx, and adds a space between values and units in condition descriptions. Diff Example <img width="2754" height="488" alt="CleanShot 2026-04-01 at 09 33 35@2x" src="https://github.com/user-attachments/assets/6502cbe9-a84d-466e-86e2-d157403759f7" /> absolute example <img width="2730" height="490" alt="CleanShot 2026-04-01 at 09 34 23@2x" src="https://github.com/user-attachments/assets/59a79c73-47d2-46ca-9832-400e36b89fbb" /> Refs EME-981 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#111994) Adds app name, platform, and bundle ID as a prefix to the evidence display text in size analysis Slack/Jira notifications. This gives recipients immediate context about which app triggered the alert without clicking through. **Before:** `Install Size, Absolute Diff > 1.0 MB (+1.0 MB)` **After:** `MyApp android (com.example.app) — Install Size, Absolute Diff > 1.0 MB (+1.0 MB)` When metadata is unavailable (e.g. no artifact info), the output is unchanged. Builds on #111660. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Allow the use of numbers in the group by (ie. numbers) so we're now returning the actual events in the groupby instead
- This adds an -if combinator to all the metric functions so that we can construct equations out of them in the new ui - Going to port this to the other datasets so we can do more interesting functions in the long term - The way this is parsed you can't do a query within a query (see the last test that checks a 400) which is intentional to keep this functionality simple
Add API pipeline steps for GitLab integration installation: InstallationConfigApiStep collects instance URL, group path, OAuth credentials, and SSL preferences. The OAuth step is late-bound via OAuth2ApiStep using config from the previous step's state. build_integration now reads token data from either the legacy state["identity"]["data"] path or the new state["oauth_data"] path so both flows work during migration. Refs VDY-39
…962) (#111981) ## What Filter snapshot-only artifacts out of the size analysis status check so they no longer show as permanently "processing." ## Why When a commit comparison has both a size analysis artifact and a snapshot artifact, the size status check counts the snapshot artifact as "1 component processing" — even though snapshots never go through the size analysis pipeline and stay in `UPLOADED` state forever. This makes the GitHub check look stuck. Fixes EME-962. ## How Added a filter in the size status check task (after building `size_metrics_map`, before the existing SKIPPED filter) that keeps only artifacts with `artifact_type` set or with size metrics present. Snapshot artifacts have neither — they have no `artifact_type` and no `PreprodArtifactSizeMetrics` rows. This mirrors the pattern already used by the snapshot status check task (`snapshots/tasks.py:138`), which filters to only artifacts with `PreprodSnapshotMetrics`. Existing tests were updated to create `PreprodArtifactSizeMetrics` for UPLOADING/UPLOADED/FAILED artifacts, matching the production flow where `create_preprod_artifact` always creates size metrics at artifact creation time.
Audit pages for layout use so that menus, headers and page contents are aligned horizontally with each other. Since many layouts use bespoke styling, this is only the first pass of pages that are easily visible by going through the list of some top level routes <img width="854" height="211" alt="CleanShot 2026-03-30 at 13 45 27" src="https://github.com/user-attachments/assets/b548dd7f-1910-4873-b979-b13796a51ffc" /> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Priscila Oliveira <priscila.oliveira@sentry.io> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jonas <JonasBa@users.noreply.github.com>
Users are sometimes confused which Seer feature is which. This makes it hard to look up the feature in the docs / get the correct support etc. This changes the sidebar to label the section with 'Seer Autofix' to make it clearer which feature this is. Before: <img width="2884" height="2016" alt="CleanShot 2026-04-01 at 10 20 54@2x" src="https://github.com/user-attachments/assets/f3831eb7-f2cc-4920-9a4d-600d2a2b5d67" /> After: <img width="2884" height="2016" alt="CleanShot 2026-04-01 at 10 21 16@2x" src="https://github.com/user-attachments/assets/8f6555c7-6898-41a3-aaae-839e1bc20dba" />
Removes border radius from page frame and aligns border <img width="2392" height="272" alt="CleanShot 2026-04-01 at 09 30 24@2x" src="https://github.com/user-attachments/assets/9a3fd3d5-a268-491e-b8f7-c51242250fa0" /> <img width="1618" height="252" alt="CleanShot 2026-04-01 at 09 30 15@2x" src="https://github.com/user-attachments/assets/f19d0f20-643b-4921-a00f-cbdf7456462b" /> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jonas <JonasBa@users.noreply.github.com>
#111691) When a coding agent integration (Cursor, Claude Code) is deleted or marked PENDING_DELETION, Seer's stored automation_handoff preference still references the old integration_id. On every subsequent automated autofix run, Seer calls Sentry's trigger_coding_agent_launch RPC with the stale ID. Sentry validates the integration, finds it gone, and raises NotFound. There are two paths that affect this, one is through the seer side root cause step and the other is after root cause completed first. To fix the first, I pulled out the NotFound error when returning to Seer and used an error code to identify it. When this is caught we clear the handoff preferences. For the second, there has been a matching change for the calling path in a separate [Seer PR](getsentry/seer#5504). Tests were added and I ran it locally to make sure it works.
Adds a new column `date_expires` to event attachments that allows us to clean them up depending on organization-specific retention settings. Existing rows default to a sentinel value that will allow us to backfill. New rows are set to 30 days from now. In a follow-up, we will fill this with the retention value passed from Relay. Note: An index on this new column is added as a dedicated post-deploy migration, since this can take a long time.
…11995) If root cause ever fail to produce an artifact, there's no reason to keep the conversation for a re-run. So remove the run id to start a fresh run.
Bump max-old-space-size from 4096 to 8192 in frontend CI workflows to give the TypeScript checker more headroom.
…#112012) Fix a bug in eap processing error ingestion. Fixes SENTRY-5KRQ
) The `TypeError: 'NoneType' object is not a mapping` occurred in the `OrganizationAutofixAutomationSettingsEndpoint.post` method when attempting to update autofix automation settings. The root cause was that `bulk_get_project_preferences()` could return `None` for projects that did not have existing preferences in the Seer API. When `existing_preferences.get(project_id_str, {})` was called for such a project, it would correctly retrieve the `None` value (as the key existed, but its value was `None`), rather than the default `{}`. Subsequently, attempting to unpack this `None` value using the `**` operator (`**existing_pref`) resulted in the `TypeError`. This fix changes the problematic line from `existing_pref = existing_preferences.get(project_id_str, {})` to `existing_pref = existing_preferences.get(project_id_str) or {}`. This ensures that if `existing_preferences.get(project_id_str)` returns `None`, `existing_pref` will be assigned an empty dictionary `{}`, allowing the dictionary unpacking to proceed safely without error. This aligns with the defensive pattern already used elsewhere in the codebase for similar scenarios. <!-- Sentry employees and contractors can delete or ignore the following. --> ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. Fixes SENTRY-5FNP --------- Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com> Co-authored-by: srest2021 <sofia.rest@sentry.io>
…mit (#111889) Add a modal in the `/_admin/` customer details page that allows staff to change the `dashboardsAsyncQueueParallelLimit` org option, which controls how many dashboard widget queries can run in parallel per org. This option was previously only settable via the API directly (`PUT /api/0/organizations/{org}/`). The new action appears in the admin customer details actions dropdown alongside existing options like "Toggle Console Platforms" and "Update Retentions". <img width="363" height="585" alt="image" src="https://github.com/user-attachments/assets/fea7a42d-17d8-416e-bf96-48bf9f420525" /> <img width="854" height="607" alt="image" src="https://github.com/user-attachments/assets/3ce6e3b8-838d-4994-9a56-033350158218" /> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…1352) This adds the ability to specify a replacement callback when defining a regex for the parameterizer. For example, a regex can now be defined like this: ParameterizationRegex( name="dog", raw_pattern=r"some pattern", replacement_callback=lambda orig_value: "<dog>" if some_condition else orig_value, ) When the parameterizer finds a matching value, instead of just reflexively replacing it with the regex's name, it'll pass the original value to the callback, and let it decide what the replacement value will be. (This is going to be necessary for us to fix our IPv6 parameterization.)
) Replace GroupList in SupergroupDetailDrawer with a custom paginated list that shows already-loaded groups from GroupStore immediately while fetching remaining groups from the API. Matched groups (from the current search) are sorted to the top and highlighted with an accent border. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…ectorSerializer (#111971) One fewer N+1.
Upgrade eslint-plugin-boundaries from 5.3.1 to 6.0.2 to resolve a
security vulnerability in the transitive handlebars dependency (4.7.8 →
4.7.9).
Migrate config to v6 conventions:
- Rename boundaries/element-types rule to boundaries/dependencies
- Update message templates from ${...} to {{...}} Handlebars syntax
- Update all eslint-disable-next-line comments to reference new rule
name
This should clear up all the `handlebars` dependabot alerts. Although
the vulnerability is critical, this is in non-production code, so
_probably_ less urgent. Still would be good to clean up dependabot
alerts though.
Co-authored-by: Claude <noreply@anthropic.com>
Missed this in my first cleanup, removed in the automator here: https://github.com/getsentry/sentry-options-automator/pull/7053/changes https://claude.ai/code/session_01VFb2jPu1DRmqNM6D57krS4 Co-authored-by: Claude <noreply@anthropic.com>
Unused, no use expected, safe to remove.
Add a DELETE method to the `OrganizationPreprodSnapshotEndpoint` so snapshot artifacts can be deleted via the API. The endpoint validates that the artifact exists, belongs to the organization, and is actually a snapshot (has `PreprodSnapshotMetrics`). It then uses the existing `delete_artifacts_and_eap_data` helper to clean up the artifact, associated files, size metrics, and EAP data in a single call. Analytics are recorded and structured logging captures the deletion details. Feature-gated behind `organizations:preprod-snapshots`. --------- Co-authored-by: Claude Opus 4.6 <noreply@example.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…recurring basis (#111958) This adds in a framework that allows us to set up a beat task that schedules a task for all rows in a given queryset. It stripes the task over the schedule period to keep load evened out. The initial usecase for this is to schedule a daily repo sync for all active integrations. <!-- Describe your PR here. -->
…112018) adds `sentry deletions list` and `sentry deletions run` commands so you can manage and execute scheduled deletions synchronously in local dev instead of waiting for the task to run. includes tests for both subcommands covering listing, filtering, and running deletions by id/model/all. wanted this for uninstalling integrations <img width="758" height="167" alt="image" src="https://github.com/user-attachments/assets/90e325b1-639f-407c-806b-caf52cbeb809" /> <img width="496" height="198" alt="image" src="https://github.com/user-attachments/assets/7db99d8e-6b7d-4f02-be1d-9a8a3bedec55" /> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This cleans up and adds some test cases to our email and URL parameterization tests. - Clarify case names. - Move broken case to known issues test. - Stop using `email.com` for URL examples, especially the ones involving the `@` sign, because it's unnecessarily confusing. - Add tests for different email address and URL formats.
Set `date_expires` explicitly when creating `EventAttachment` records during event ingestion, using `retention_days` from the `CachedAttachment`. This ensures each new attachment row carries an accurate expiry derived from the project's configured retention rather than relying on the sentinel value added in #111881.
…111948) In #111352, we added the ability for a `ParameterizationRegex` to use a callback for its replacement value, rather than just always replacing the original value with `<regex type>`. One thing this will let us do is make the replacement conditional, by having the callback return the original value if it decides the replacement shouldn't be made. (This is how our improved IPv6 parameterization is going to work, so that we can let Python's built-in `ipaddress` functions have the final word on whether or not an ip-like string is a valid IPv6 address.) That's all very well and good in cases where the callback agrees that the original value should be replaced. When it decides _not_ to replace the value, though, we've created a problem for ourselves. Continuing with the IP example, say we encounter a string like `11:21:99`, which looks vaguely IPv6-ish, but isn't in fact a valid IP. Before the aforementioned PR, when we were strictly using a `named_pattern_1 | named_pattern_2 | named_pattern_3`-type regex for replacement, parameterization looked like this: - The regex engine tests the string against the `ip` pattern, sees that it doesn't actually match, and keeps trying alternatives. - The regex engine tests the string against the `int` pattern, finds three matches, and makes the replacements. - Final result: `<int>:<int>:<int>` (Yay, the right answer!) With that change in place, though, once the `ip` pattern uses regex to find IP-like strings and then confirms the match using a callback, parameterization will look like this: - The regex engine tests the string against the `ip-like` pattern, finds a match, and passes it to the callback. - The callback tests the string, finds it's not actually a valid IPv6 address, and returns the original string as the "replacement" value. - As far as the regex engine is concerned, a match has been found, so no other patterns are tried. - Final result: `11:21:99` (Boo, the wrong answer.) To be clear, even with that change in place, we're not actually running into this problem in prod (yet), because the IP regex hasn't yet had the callback added to it. But we will unless we fix the problem, which is what this PR does. In cases where detect such a false positive, we'll now fall back to checking each pattern individually. Essentially, we're just taking control of whether or not to continue checking patterns away from the regex engine, and always forcing every pattern to be checked. While this double-parameterization does take more time, a) we expect this to be a fairly uncommon edge case, b) we recently saved a bunch of time by caching parameterization results, so we have a little wiggle room, and c) we're talking an extra half-millisecond on average, so it'll still be quite fast. Note: There's not yet a test for this behavior, because testing it requires having something to test. Rather than more or less recreating everything the upcoming IP change will include, I decided to just hold off adding a test until that PR (which is now up at #111979). For now, since there are no live callbacks, all we really need to know is that this change doesn't crash the normal running of the parameterizer, which is amply demonstrated by the fact that every other parameterization test still works.
…to original field (#111934) Context in linear ticket: [DAIN-1417](https://linear.app/getsentry/issue/DAIN-1417/visualize-drag-and-drop-shows-wrong-cursor-and-ghost-position) the drag and drop ghost field was always shifted a lot further to the right than the original field. This happened because the widget builder slideout has transitions applied to it already which then applies to all nested components. This means that the drag and drop context was applying the transformation calculations on top of the exisiting x/y values but we need it to apply to when x/y=0. I've added in a modifier function to adjust the x and y coordinates of the drag overlay so that the drag button aligns with the cursor. Here's working proof: https://github.com/user-attachments/assets/b02d887c-cb0c-4ab5-a047-0aa4b32344e4
#112035) For logs/discover/issues, `enableAiSearch` is = this flag being on. The combobox components are never shown unless enableAiSearch (condition right above usePollingEndpoint), so the !usePollingEndpoint is a dead branch. In general this FF is a killswitch for the whole ai search feature, not a polling variant. The polling toggle only works for spans, the only dataset that has a sync implementation
With getsentry/sentry-options-automator#7061 we're starting to roll the Ask Seer feature out to EA for logs/issues/discover, and it's now considered beta
Follow-up to #111881. Backfills all existing rows with that sentinel to `date_added + 30 days`, aligning them with the default attachment retention period. New rows will be written with a date_expires. --------- Co-authored-by: Claude <noreply@anthropic.com>
…111972) Adds objectstore cleanup to the artifact deletion path in `delete_artifacts_and_eap_data`. Previously, only DB records and EAP trace data were cleaned up when deleting preprod artifacts. Snapshot images, manifests, comparison manifests, and diff masks stored in objectstore were left to expire via 30-day TTL — meaning deleted snapshot data remained accessible for up to a month. Now, before the DB cascade runs, we read each snapshot's manifest to discover all associated objectstore keys (individual images by content hash, the manifest itself, comparison manifests, and diff mask PNGs), deduplicate them, and delete them in parallel using `ContextPropagatingThreadPoolExecutor(max_workers=8)`. Individual key deletion failures are logged but non-blocking since TTL expiration serves as the fallback. The implementation is split into three module-level functions: - `_collect_snapshot_objectstore_keys` — queries snapshot metrics and comparisons, reads manifests to enumerate all keys - `_delete_objectstore_key` — thread worker that deletes a single key - `_delete_snapshot_objectstore_data` — orchestrator that deduplicates keys and dispatches parallel deletes --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Claude Opus 4.6 <noreply@example.com>
Currently GitHub Copilot coding agent handoff is a permission set at the user-level as users must choose to connect their github account. However, after some discussion we think copilot integration should have to be allowed at the organization admin in line with how cursor and claude operate. Since copilot does not need an api key or any credentials, this PR creates a DirectEnableIntegration which skips the pop up stage and enables the integration. Only if this is enabled are users within the org provided access to "Setup/Send to GitHub Copilot" option for the handoff dropdown. This is an intermediate fix for now. There are several changes planned for coding integration settings that would likely make this unnecessary. Additionally, we only launched EA of copilot in the last couple of weeks, this should not be merged or put out until we decide how we would like to inform our current users that this will break their setup (minimally). This backend PR will be followed by a frontend one. https://github.com/user-attachments/assets/24f3c665-0ae8-4a4b-8347-5c92752f3d56 --------- Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
…prompts (#111957) Extends the `/dashboard/generate` endpoint to accept a current dashboard parameter as json. When a dashboard is provided, the seer run is prompted to edit the existing dashboard.
Adds a fallback function to fill in missing attributes from generated dashboards from seer. Currently applies a default layout, limit, and minH if missing. These attributes are marked as required by the artifact schema, but Seer does not always create them
Improve the loading state by using loading text instead of the ghost to make it more obvious we're still in a loading state. # Screenshots ## Drawer | Root Cause | Plan | Code Changes | | ----------- | ----- | -------------- | | <img width="1130" height="590" alt="image" src="https://github.com/user-attachments/assets/aecf3536-4a0b-4c31-9cb1-c79ea78124e9" /> | <img width="1130" height="402" alt="image" src="https://github.com/user-attachments/assets/4e462a27-ebf2-47e7-85b9-c40c5735cbff" /> | <img width="1130" height="402" alt="image" src="https://github.com/user-attachments/assets/e5d177d9-0ff5-43ae-bf56-99bf2937601f" /> | ## Sidebar | Root Cause | Plan | Code Changes | | ----------- | ----- | -------------- | | <img width="554" height="132" alt="image" src="https://github.com/user-attachments/assets/82d074d7-763d-44ea-be8f-310cc4f2ef78" /> | <img width="554" height="130" alt="image" src="https://github.com/user-attachments/assets/7a8eed65-f9f8-4ae2-bb9a-1f32f0461055" /> | <img width="554" height="130" alt="image" src="https://github.com/user-attachments/assets/f5c92318-7c45-49a7-9cd6-8b21d7ee587e" /> |
…111925) Follow up to #111760 to create and update `DetectorWorkflow`s in the `BaseDetectorTypeValidator` rather than in a separate `BulkDetectorWorkflowsValidator` mainly for the purpose of having correct API docs (the `workflow_ids` param is not listed in the detector POST and PUT docs) but this also makes the code a bit simpler.
…111975) Create `NEEDS_APPROVAL` records in the snapshot status check task when visual changes are detected, so artifacts requiring review are tracked before a user explicitly acts. Clean up these records when approvals arrive via the GitHub check run webhook. ALSO: Reorders the task so approval/change-detection logic runs **before** the repository/client lookup — NEEDS_APPROVAL records are now persisted even when the VCS integration lookup fails. Also removes NEEDS_APPROVAL creation from the size status check task — approvals only apply to snapshots. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Closes EME-991 ## Summary - Pass the `display` query parameter to the builds API from the Mobile Builds settings page - The Size Analysis section sends `display=size` and the Build Distribution section sends `display=distribution` - This filters out snapshot-only builds from both lists, matching the filtering already used on the explore/releases page Previously both sections fetched all builds without any display filtering, so snapshot builds would appear in the size and distribution lists.
Turn the React Aria missing textValue warning into a hard Jest failure and add the text values exercised by the affected UI tests --------- Co-authored-by: Codex <codex@openai.com>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )