Repository navigation
feat(events): Put scope values in event data and filters - #2399
Merged
Merged
Conversation
Every GitHub, Sentry, Vercel, and Linear event now sets its scope values in trusted data, and each one is a declared filter with an events list. Scope values use the same case as identifiers, so a saved identifier can later become exact filters. Core triggers, identifiers, watches, and matching do not change. Each event kind builds its data through one Zod schema. The shared filter-event test helper now checks each value against the filter kind, enum, and list. Refs #2362 Co-Authored-By: David Cramer <david@sentry.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Sentry Evalsjunior-behavioral
Base commit junior-guardian
Base commit junior-integration
Base commit |
Sentry issue events declare an issueId filter, and Linear issue events declare issueIdentifier and build their data with a strict schema. Sentry events drop org, because one integration belongs to one org. GitHub release tags are no longer URI-encoded in data; only ASCII letters are lowercased. A blank tag is skipped. Deployment environments are trimmed like the identifier. Ready-for-review data and lookup values go through strict schemas. Vercel filters list their events. A shared test helper checks, in each plugin, that every identifier turns into filters that match its own events and no others. Co-Authored-By: David Cramer <david@sentry.io>
Contributor
|
106 screenshot changes — 0 changed · 106 added · 0 removed |
dcramer
marked this pull request as ready for review
October 30, 2026 01:38
dcramer
approved these changes
Oct 30, 2026
This branch was successfully deployed
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.
Refs #2362 (item 7, slice A).
Item 7 makes an event automation trigger
namespace + events + match, with scope as optional filters. This slice is the prerequisite: every event now sets its scope values in trusteddata, and each value is a declared filter with a correcteventslist. A new test in each plugin proves that every identifier can become filters that select the same events, and never more. Core triggers, identifiers, watches, matching, and saved rows do not change. Existing watches and automations behave the same; new filters become available.Per service
GitHub
repoon every event (deployment, issue, pull request, release).pullRequeston pull request events. A check suite that GitHub links to no pull request (main-branch builds) has none.pullRequeststays listed forpull_request.checks.*, because suites linked to a pull request set it, and anowner/repo#nidentifier must convert torepo+pullRequestfor check events.issueon issue events.commitShaon deployment and check suite events, only for a full SHA. Check suite data usedheadSha, which could be short and mixed case. A check suite with a short SHA carries nocommitSha. This is on purpose: a short SHA cannot match a full one exactly.deploymentIdon deployment events, to match Vercel.environmentis trimmed, then lowercased, the same as the identifier. Before, data kept spaces that the identifier dropped.tagonrelease.published, which had no data before. See "Case decisions".isDraft: false) now goes throughpullRequestEventDatatoo. The lazyopenerUsername,openerRole, andauthorsvalues go through a strict lookup schema inpull-request-match-data.ts. Check suite data dropsscope: "check_suite", a constant that the event type already says.suiteConclusionstays as a detail, not a filter.GITHUB_ISSUE_COMMENT_MATCH_FIELDSis nowGITHUB_ISSUE_MATCH_FIELDS.release_sourcenow has match fields.Sentry
projectson issue and metric alert events, andissueIdon issue events (new filter).projectsis alist: truefield on both. An issue has a one-item list. One list key fits both because theprojectresource type gets both kinds of event, andmergeEventMatchFieldsneeds one kind.orgis not in data and is not a filter. Since ref(sentry): Remove SENTRY_WEBHOOK_ORG #2386, one Sentry internal integration belongs to one org, and its webhook secret scopes every delivery to that org. Soorgis the same on every event of an install, and a filter on it can never narrow anything.orgstays in identifiers for now, because saved Watches use those strings. Changing them is a separate decision./api/0/organizations/<org>/issues/...), and the alert hasalert_rule.organization_id(a number) andweb_url. Only the installation webhook hasinstallation.organization.slug, and the plugin does not store it. So the plugin still reads the org from the URL, but only to build identifiers and to ignore payloads with no readable org (ref(sentry): Remove SENTRY_WEBHOOK_ORG #2386 behavior). That parsing is now one Zod-checked function,organizationSlug, with a comment that says why.issueandmetric_alertresource types now declare their match fields.Vercel:
projectIdin data and as a filter.deploymentIdis now a filter too. Data goes through a Zod schema. All four filters now list their events, like the other plugins. I did not add team: identifiers do not include it, and project ids are unique.Linear:
issueIdentifieris now a filter (uppercase, such asSRE-123).teamKeyhas aneventslist, so the slice B namespace merge works. Issue data is built with a strict Zod schema, like the other plugins.GitHub and Sentry now use one order: drop missing values first, then parse with the strict schema (
definedValuesbefore.parse).Case decisions
Scope values use the same form as identifiers, so a saved identifier can convert to exact filters. GitHub and Sentry lowercase every identifier, so
repo,commitSha,projects, andenvironmentare lowercase. This also changes existingdata.repo, which copiedfull_nameunchanged. GitHub ignores case in repo names, and the plugin's DB lookups already lowercase. Vercel ids keep their case (no identifier normalization). Linear values stay uppercase.Release
tagis the trimmed tag with only ASCII letters lowercased. It is not URI-encoded, so people and agents filter onrelease/1.0, notrelease%2f1.0. The release-source identifier has the URI-encoded tag, and the plugin lowercases the whole identifier. Encoding turns every non-ASCII character into%XX, so only ASCII letters change case there. Conversion must decode the identifier's tag part (and the environment part of a deployment-source identifier). The comment ongitHubReleaseTagDataSchemasays this. A non-ASCII tag stays exact:Üandüstay different. The raw tag also stays in the untrusted text. Trade-off: tag text from people is now in trusted data. Git tags cannot hold spaces or control characters, so that text is short.A blank tag (only spaces) cannot happen on GitHub, but if one arrives, the release event is skipped. It no longer throws and fails the delivery.
Declaring
repomakes older saved rows that already filter onrepovalid again. That is expected.Notes for slice C (conversion)
org/projectconverts toprojects: [project], andorg/project#issueIdtoprojects: [project]+issueId. The org part is dropped, because the install already fixes it.metric-alert:org/idconverts toalertRuleId.projectsis left out. Estimated threshold: about 72 projects with 50-character slugs. A convertedorg/projecttrigger then misses those alerts. It never widens. David accepted this limit. Slice C must keep this rule: keep the identifier for that case or block the row, never widen.commitSha, so a commit filter does not match it.Tests
identifierMatchMismatchesin@sentry/junior-testing/event-filters, next tofilterEventMismatches. Each plugin passes its published events, a conversion function, andeventMatchesfrom plugin-api. For every event, the match of its identifier must use only filters that the plugin declares for that event type, must match the event, and must not match any event of the same type that did not go to that identifier. Every event needs such an other event, so the fixtures differ in each identifier part (same parent with another leaf, and another parent)./and a non-ASCII letter, two tags that differ only in a non-ASCII letter, and an environment with spaces. The new test fails without the SentryissueIdfilter, without the LinearissueIdentifierfilter, with URI-encoded tags, and without the environment trim. I checked each of these.tests/event-data.test.ts, shared by the filter test and the conversion test.github-plugin.test.tsis 229 lines shorter.filterEventMismatcheschecks each value per event against the field'skind,enum, andlist, beside theeventslist check. A blank-tag release case was added.Ran:
pnpm typecheck,pnpm lint, the GitHub (255), Sentry (22), Vercel (33), and Linear (10) suites, and the core events/automations tests. One core test,event-automations > delivers the current automation card, fails in my sandbox onmaintoo, because the title comes back generated.CI on
da00392aa:ci / requiredand every other check pass. All eval suites ran on this head: guardian 94/94, integration 102/102, and behavioral 81/83, which is above its score floor (behavioral / scorepasses). The two behavioral misses areskills/routing.eval.ts(user-callable skill rejection) andgoogle/scheduling.eval.ts(recurring two-person slot). This PR does not touch either area. Theevalssummary check is still pending. It waits to compare with an eval run on the base commit2236380, and no eval run exists for that commit onmain.Notes and follow-ups
authors/opener*), and required scope filters per event (for example,repoon comment events).via David Cramer.
--
View Session [Sentry]