def get(self, request: Request, project) -> Response: context = serialize( [plugin for plugin in plugins.configurable_for_project(project, version=None)], request.user, PluginSerializer(project), ) return Response(context)
def plugin_issues(self, request, group, plugin_issues, **kwargs): if not self.is_configured(request=request, project=group.project): return plugin_issues prefix = self.get_conf_key() issue_id = GroupMeta.objects.get_value(group, '%s:tid' % prefix, None) item = { 'slug': self.slug, 'allowed_actions': self.allowed_actions, # TODO(dcramer): remove in Sentry 8.22+ 'title': self.get_title(), 'name': self.get_title(), 'shortName': self.get_short_title(), } if issue_id: item['issue'] = { 'issue_id': issue_id, 'url': self.get_issue_url(group=group, issue_id=issue_id), 'label': self.get_issue_label(group=group, issue_id=issue_id), } item.update( PluginSerializer(group.project).serialize(self, None, request.user)) plugin_issues.append(item) return plugin_issues
def get(self, request, organization): all_plugins = dict([(p.slug, p) for p in plugins.all()]) if 'plugins' in request.GET: if request.GET.get('plugins') == '_all': return Response( serialize([p for p in plugins.all()], request.user, PluginSerializer())) desired_plugins = set(request.GET.getlist('plugins')) else: desired_plugins = set(all_plugins.keys()) # Ignore plugins that are not available to this Sentry install. desired_plugins = desired_plugins & set(all_plugins.keys()) # Each tuple represents an enabled Plugin (of only the ones we care # about) and its corresponding Project. enabled_plugins = ProjectOption.objects.filter( key__in=['%s:enabled' % slug for slug in desired_plugins], project__organization=organization, ).select_related('project') resources = [] for project_option in enabled_plugins: resources.append( serialize( all_plugins[project_option.key.split(':')[0]], request.user, OrganizationPluginSerializer(project_option.project), )) return Response(resources)
def _get_context_plugins(self, request, group): project = group.project return serialize([ plugin for plugin in plugins.for_project(project, version=None) if plugin.has_project_conf() and hasattr(plugin, 'get_custom_contexts') and plugin.get_custom_contexts() ], request.user, PluginSerializer(project))
def get(self, request, project, plugin_id): plugin = self._get_plugin(plugin_id) try: context = serialize(plugin, request.user, PluginWithConfigSerializer(project)) except PluginIdentityRequired as e: context = serialize(plugin, request.user, PluginSerializer(project)) context["config_error"] = six.text_type(e) context["auth_url"] = reverse("socialauth_associate", args=[plugin.slug]) return Response(context)
def get(self, request, project): """ Retrieve a Project `````````````````` Return details on an individual project. :pparam string organization_slug: the slug of the organization the project belongs to. :pparam string project_slug: the slug of the project to delete. :auth: required """ data = serialize(project, request.user) data['options'] = { 'sentry:origins': '\n'.join(project.get_option('sentry:origins', ['*']) or []), 'sentry:resolve_age': int(project.get_option('sentry:resolve_age', 0)), 'sentry:scrub_data': bool(project.get_option('sentry:scrub_data', True)), 'sentry:scrub_defaults': bool(project.get_option('sentry:scrub_defaults', True)), 'sentry:safe_fields': project.get_option('sentry:safe_fields', []), 'sentry:sensitive_fields': project.get_option('sentry:sensitive_fields', []), 'sentry:csp_ignored_sources_defaults': bool(project.get_option('sentry:csp_ignored_sources_defaults', True)), 'sentry:csp_ignored_sources': '\n'.join(project.get_option('sentry:csp_ignored_sources', []) or []), 'sentry:default_environment': project.get_option('sentry:default_environment'), 'sentry:reprocessing_show_hint': bool(project.get_option('sentry:reprocessing_show_hint', True)), 'sentry:reprocessing_active': bool(project.get_option('sentry:reprocessing_active', False)), 'filters:blacklisted_ips': '\n'.join(project.get_option('sentry:blacklisted_ips', [])), 'feedback:branding': project.get_option('feedback:branding', '1') == '1', } data['plugins'] = serialize([ plugin for plugin in plugins.configurable_for_project(project, version=None) if plugin.has_project_conf() ], request.user, PluginSerializer(project)) data['team'] = serialize(project.team, request.user) data['organization'] = serialize(project.organization, request.user) data.update({ 'digestsMinDelay': project.get_option( 'digests:mail:minimum_delay', digests.minimum_delay, ), 'digestsMaxDelay': project.get_option( 'digests:mail:maximum_delay', digests.maximum_delay, ), 'subjectPrefix': project.get_option('mail:subject_prefix'), 'subjectTemplate': project.get_option('mail:subject_template') or DEFAULT_SUBJECT_TEMPLATE.template, }) include = set(filter(bool, request.GET.get('include', '').split(','))) if 'stats' in include: data['stats'] = { 'unresolved': self._get_unresolved_count(project), } return Response(data)
def get(self, request, project): """ Retrieve a Project `````````````````` Return details on an individual project. :pparam string organization_slug: the slug of the organization the project belongs to. :pparam string project_slug: the slug of the project to delete. :auth: required """ data = serialize(project, request.user) data['options'] = { 'sentry:origins': '\n'.join(project.get_option('sentry:origins', ['*']) or []), 'sentry:resolve_age': int(project.get_option('sentry:resolve_age', 0)), 'sentry:scrub_data': bool(project.get_option('sentry:scrub_data', True)), 'sentry:scrub_defaults': bool(project.get_option('sentry:scrub_defaults', True)), 'sentry:sensitive_fields': project.get_option('sentry:sensitive_fields', []), 'sentry:csp_ignored_sources_defaults': bool( project.get_option('sentry:csp_ignored_sources_defaults', True)), 'sentry:csp_ignored_sources': '\n'.join( project.get_option('sentry:csp_ignored_sources', []) or []), 'sentry:default_environment': project.get_option('sentry:default_environment'), 'feedback:branding': project.get_option('feedback:branding', '1') == '1', } data['plugins'] = serialize([ plugin for plugin in plugins.configurable_for_project( project, version=None) if plugin.has_project_conf() ], request.user, PluginSerializer(project)) data['team'] = serialize(project.team, request.user) data['organization'] = serialize(project.organization, request.user) include = set(filter(bool, request.GET.get('include', '').split(','))) if 'stats' in include: data['stats'] = { 'unresolved': self._get_unresolved_count(project), } return Response(data)
def get(self, request, project, plugin_id): plugin = self._get_plugin(plugin_id) try: context = serialize(plugin, request.user, PluginWithConfigSerializer(project)) except PluginIdentityRequired as e: context = serialize(plugin, request.user, PluginSerializer(project)) context['config_error'] = e.message context['auth_url'] = reverse('socialauth_associate', args=[plugin.slug]) return Response(context)
def get(self, request: Request, project, plugin_id) -> Response: plugin = self._get_plugin(plugin_id) try: context = serialize(plugin, request.user, PluginWithConfigSerializer(project)) except PluginIdentityRequired as e: context = serialize(plugin, request.user, PluginSerializer(project)) context["config_error"] = str(e) context["auth_url"] = reverse("socialauth_associate", args=[plugin.slug]) if context["isDeprecated"]: raise Http404 return Response(context)
def handle(self, request, organization, team, project): if request.method == 'POST': op = request.POST.get('op') if op == 'enable': self._handle_enable_plugin(request, project) return HttpResponseRedirect(request.path) elif op == 'disable': self._handle_disable_plugin(request, project) return HttpResponseRedirect(request.path) enabled_plugins = [] other_plugins = [] issue_v2_plugins = [] for plugin in self._iter_plugins(): if plugin.is_enabled(project): if isinstance(plugin, IssueTrackingPlugin2): issue_v2_plugins.append(plugin) continue content = plugin.get_issue_doc_html() form = plugin.project_conf_form if form is not None: view = plugin.configure(request=request, project=project) if isinstance(view, HttpResponse): return view elif content: enabled_plugins.append((plugin, mark_safe(content))) enabled_plugins.append((plugin, mark_safe(content + view))) elif plugin.can_configure_for_project(project): other_plugins.append(plugin) context = { 'page': 'issue-tracking', 'enabled_plugins': enabled_plugins, 'other_plugins': other_plugins, 'issue_v2_plugins': serialize(issue_v2_plugins, request.user, PluginSerializer(project=project)), } return self.respond('sentry/project-issue-tracking.html', context)
def plugin_issues(self, request, group, plugin_issues, **kwargs): if not self.is_configured(request=request, project=group.project): return plugin_issues item = { 'slug': self.slug, 'allowed_actions': self.allowed_actions, 'title': self.get_title() } issue = self.build_issue(group) if issue: item['issue'] = { 'issue_id': issue.get('id'), 'url': self._get_issue_url_compat(group, issue), 'label': self._get_issue_label_compat(group, issue), } item.update(PluginSerializer(group.project).serialize(self, None, request.user)) plugin_issues.append(item) return plugin_issues
def plugin_issues(self, request, group, plugin_issues, **kwargs): if not self.is_configured(request=request, project=group.project): return plugin_issues item = { "slug": self.slug, "allowed_actions": self.allowed_actions, "title": self.get_title(), } issue = self.build_issue(group) if issue: item["issue"] = { "issue_id": issue.get("id"), "url": self._get_issue_url_compat(group, issue), "label": self._get_issue_label_compat(group, issue), } item.update(PluginSerializer(group.project).serialize(self, None, request.user)) plugin_issues.append(item) return plugin_issues
def serialize(self, obj, attrs, user): from sentry.plugins import plugins data = super(DetailedProjectSerializer, self).serialize( obj, attrs, user ) data.update({ 'latestRelease': attrs['latest_release'], 'options': { 'sentry:origins': '\n'.join(attrs['options'].get('sentry:origins', ['*']) or []), 'sentry:resolve_age': int(attrs['options'].get('sentry:resolve_age', 0)), 'sentry:scrub_data': bool(attrs['options'].get('sentry:scrub_data', True)), 'sentry:scrub_defaults': bool(attrs['options'].get('sentry:scrub_defaults', True)), 'sentry:safe_fields': attrs['options'].get('sentry:safe_fields', []), 'sentry:sensitive_fields': attrs['options'].get('sentry:sensitive_fields', []), 'sentry:csp_ignored_sources_defaults': bool(attrs['options'].get('sentry:csp_ignored_sources_defaults', True)), 'sentry:csp_ignored_sources': '\n'.join(attrs['options'].get('sentry:csp_ignored_sources', []) or []), 'sentry:reprocessing_active': bool(attrs['options'].get('sentry:reprocessing_active', False)), 'filters:blacklisted_ips': '\n'.join(attrs['options'].get('sentry:blacklisted_ips', [])), 'feedback:branding': attrs['options'].get('feedback:branding', '1') == '1', }, 'digestsMinDelay': attrs['options'].get( 'digests:mail:minimum_delay', digests.minimum_delay, ), 'digestsMaxDelay': attrs['options'].get( 'digests:mail:maximum_delay', digests.maximum_delay, ), 'subjectPrefix': attrs['options'].get('mail:subject_prefix'), 'subjectTemplate': attrs['options'].get('mail:subject_template') or DEFAULT_SUBJECT_TEMPLATE.template, 'organization': attrs['org'], 'plugins': serialize([ plugin for plugin in plugins.configurable_for_project(obj, version=None) if plugin.has_project_conf() ], user, PluginSerializer(obj)), 'platforms': attrs['platforms'], 'processingIssues': attrs['processing_issues'], 'defaultEnvironment': attrs['options'].get('default_environment'), }) return data
def serialize(self, obj, attrs, user): from sentry.plugins.base import plugins def get_value_with_default(key): value = attrs["options"].get(key) if value is not None: return value return projectoptions.get_well_known_default( key, epoch=attrs["options"].get("sentry:option-epoch")) data = super(DetailedProjectSerializer, self).serialize(obj, attrs, user) data.update({ "latestRelease": attrs["latest_release"], "options": { "sentry:csp_ignored_sources_defaults": bool(attrs["options"].get( "sentry:csp_ignored_sources_defaults", True)), "sentry:csp_ignored_sources": "\n".join( attrs["options"].get("sentry:csp_ignored_sources", []) or []), "sentry:reprocessing_active": bool(attrs["options"].get("sentry:reprocessing_active", False)), "filters:blacklisted_ips": "\n".join(attrs["options"].get("sentry:blacklisted_ips", [])), u"filters:{}".format(FilterTypes.RELEASES): "\n".join(attrs["options"].get( u"sentry:{}".format(FilterTypes.RELEASES), [])), u"filters:{}".format(FilterTypes.ERROR_MESSAGES): "\n".join(attrs["options"].get( u"sentry:{}".format(FilterTypes.ERROR_MESSAGES), [])), "feedback:branding": attrs["options"].get("feedback:branding", "1") == "1", }, "digestsMinDelay": attrs["options"].get("digests:mail:minimum_delay", digests.minimum_delay), "digestsMaxDelay": attrs["options"].get("digests:mail:maximum_delay", digests.maximum_delay), "subjectPrefix": attrs["options"].get("mail:subject_prefix", options.get("mail.subject-prefix")), "allowedDomains": attrs["options"].get("sentry:origins", ["*"]), "resolveAge": int(attrs["options"].get("sentry:resolve_age", 0)), "dataScrubber": bool(attrs["options"].get("sentry:scrub_data", True)), "dataScrubberDefaults": bool(attrs["options"].get("sentry:scrub_defaults", True)), "safeFields": attrs["options"].get("sentry:safe_fields", []), "storeCrashReports": bool(attrs["options"].get("sentry:store_crash_reports", False)), "sensitiveFields": attrs["options"].get("sentry:sensitive_fields", []), "subjectTemplate": attrs["options"].get("mail:subject_template") or DEFAULT_SUBJECT_TEMPLATE.template, "securityToken": attrs["options"].get("sentry:token") or obj.get_security_token(), "securityTokenHeader": attrs["options"].get("sentry:token_header"), "verifySSL": bool(attrs["options"].get("sentry:verify_ssl", False)), "scrubIPAddresses": bool(attrs["options"].get("sentry:scrub_ip_address", False)), "scrapeJavaScript": bool(attrs["options"].get("sentry:scrape_javascript", True)), "groupingConfig": get_value_with_default("sentry:grouping_config"), "groupingEnhancements": get_value_with_default("sentry:grouping_enhancements"), "groupingEnhancementsBase": get_value_with_default("sentry:grouping_enhancements_base"), "fingerprintingRules": get_value_with_default("sentry:fingerprinting_rules"), "organization": attrs["org"], "plugins": serialize( [ plugin for plugin in plugins.configurable_for_project( obj, version=None) if plugin.has_project_conf() ], user, PluginSerializer(obj), ), "platforms": attrs["platforms"], "processingIssues": attrs["processing_issues"], "defaultEnvironment": attrs["options"].get("sentry:default_environment"), "relayPiiConfig": attrs["options"].get("sentry:relay_pii_config"), "builtinSymbolSources": get_value_with_default("sentry:builtin_symbol_sources"), "symbolSources": attrs["options"].get("sentry:symbol_sources"), }) return data
def serialize(self, obj, attrs, user): from sentry.plugins import plugins data = super(DetailedProjectSerializer, self).serialize(obj, attrs, user) data.update( { 'latestRelease': attrs['latest_release'], 'options': { 'sentry:csp_ignored_sources_defaults': bool(attrs['options'].get( 'sentry:csp_ignored_sources_defaults', True)), 'sentry:csp_ignored_sources': '\n'.join(attrs['options'].get( 'sentry:csp_ignored_sources', []) or []), 'sentry:reprocessing_active': bool(attrs['options'].get( 'sentry:reprocessing_active', False)), 'filters:blacklisted_ips': '\n'.join(attrs['options'].get( 'sentry:blacklisted_ips', [])), u'filters:{}'.format(FilterTypes.RELEASES): '\n'.join(attrs['options'].get( u'sentry:{}'.format(FilterTypes.RELEASES), [])), u'filters:{}'.format(FilterTypes.ERROR_MESSAGES): '\n'. join(attrs['options'].get(u'sentry:{}'.format( FilterTypes.ERROR_MESSAGES), [])), 'feedback:branding': attrs['options'].get('feedback:branding', '1') == '1', }, 'digestsMinDelay': attrs['options'].get( 'digests:mail:minimum_delay', digests.minimum_delay, ), 'digestsMaxDelay': attrs['options'].get( 'digests:mail:maximum_delay', digests.maximum_delay, ), 'subjectPrefix': attrs['options'].get('mail:subject_prefix', options.get('mail.subject-prefix')), 'allowedDomains': attrs['options'].get( 'sentry:origins', ['*']), 'resolveAge': int(attrs['options'].get('sentry:resolve_age', 0)), 'dataScrubber': bool(attrs['options'].get('sentry:scrub_data', True)), 'dataScrubberDefaults': bool(attrs['options'].get('sentry:scrub_defaults', True)), 'safeFields': attrs['options'].get('sentry:safe_fields', []), 'storeCrashReports': bool(attrs['options'].get('sentry:store_crash_reports', False)), 'sensitiveFields': attrs['options'].get('sentry:sensitive_fields', []), 'subjectTemplate': attrs['options'].get( 'mail:subject_template') or DEFAULT_SUBJECT_TEMPLATE.template, 'securityToken': attrs['options'].get('sentry:token') or obj.get_security_token(), 'securityTokenHeader': attrs['options'].get('sentry:token_header'), 'verifySSL': bool(attrs['options'].get('sentry:verify_ssl', False)), 'scrubIPAddresses': bool(attrs['options'].get('sentry:scrub_ip_address', False)), 'scrapeJavaScript': bool(attrs['options'].get('sentry:scrape_javascript', True)), 'organization': attrs['org'], 'plugins': serialize( [ plugin for plugin in plugins.configurable_for_project(obj, version=None) if plugin.has_project_conf() ], user, PluginSerializer(obj) ), 'platforms': attrs['platforms'], 'processingIssues': attrs['processing_issues'], 'defaultEnvironment': attrs['options'].get('sentry:default_environment'), 'relayPiiConfig': attrs['options'].get('sentry:relay_pii_config'), } ) return data
def get(self, request, project): context = serialize([ plugin for plugin in plugins.configurable_for_project( project, version=None) if plugin.has_project_conf() ], request.user, PluginSerializer(project)) return Response(context)
def get(self, request, organization): """ List one or more plugin configurations, including a `projectList` for each plugin which contains all the projects that have that specific plugin both configured and enabled. - similar to the `OrganizationPluginsEndpoint`, and can eventually replace it :qparam plugins array[string]: an optional list of plugin ids (slugs) if you want specific plugins. If not set, will return configurations for all plugins. """ desired_plugins = [] for slug in request.GET.getlist("plugins") or (): # if the user request a plugin that doesn't exist, throw 404 try: desired_plugins.append(plugins.get(slug)) except KeyError: return Response({"detail": "Plugin %s not found" % slug}, status=404) # if no plugins were specified, grab all plugins but limit by those that have the ability to be configured if not desired_plugins: desired_plugins = list(plugins.plugin_that_can_be_configured()) # `keys_to_check` are the ProjectOption keys that tell us if a plugin is enabled (e.g. `plugin:enabled`) or are # configured properly, meaning they have the required information - plugin.required_field - needed for the # plugin to work (ex:`opsgenie:api_key`) keys_to_check = [] for plugin in desired_plugins: keys_to_check.append("%s:enabled" % plugin.slug) if plugin.required_field: keys_to_check.append("%s:%s" % (plugin.slug, plugin.required_field)) # Get all the project options for org that have truthy values project_options = ProjectOption.objects.filter( key__in=keys_to_check, project__organization=organization ).exclude(value__in=[False, ""]) """ This map stores info about whether a plugin is configured and/or enabled { "plugin_slug": { "project_id": { "enabled": True, "configured": False }, }, } """ info_by_plugin_project = {} for project_option in project_options: [slug, field] = project_option.key.split(":") project_id = project_option.project_id # first add to the set of all projects by plugin info_by_plugin_project.setdefault(slug, {}).setdefault( project_id, {"enabled": False, "configured": False} ) # next check if enabled if field == "enabled": info_by_plugin_project[slug][project_id]["enabled"] = True # if the projectoption is not the enable field, it's configuration field else: info_by_plugin_project[slug][project_id]["configured"] = True # get the IDs of all projects for found project options and grab them from the DB project_id_set = set([project_option.project_id for project_option in project_options]) projects = Project.objects.filter(id__in=project_id_set, status=ObjectStatus.VISIBLE) # create a key/value map of our projects project_map = {project.id: project for project in projects} # iterate through the desired plugins and serialize them serialized_plugins = [] for plugin in desired_plugins: serialized_plugin = serialize(plugin, request.user, PluginSerializer()) serialized_plugin["projectList"] = [] info_by_project = info_by_plugin_project.get(plugin.slug, {}) # iterate through the projects for project_id, plugin_info in six.iteritems(info_by_project): # if the project is being deleted if project_id not in project_map: continue project = project_map[project_id] # only include plugins which are configured if not plugin_info["configured"]: continue serialized_plugin["projectList"].append( { "projectId": project.id, "projectSlug": project.slug, "projectName": project.name, # TODO(steve): do we need? "enabled": plugin_info["enabled"], "configured": plugin_info["configured"], # TODO(steve): do we need? "projectPlatform": project.platform, } ) # sort by the projectSlug serialized_plugin["projectList"].sort(key=lambda x: x["projectSlug"]) serialized_plugins.append(serialized_plugin) return Response(serialized_plugins)
def serialize(self, obj, attrs, user): from sentry.plugins.base import plugins def get_value_with_default(key): value = attrs["options"].get(key) if value is not None: return value return projectoptions.get_well_known_default( key, epoch=attrs["options"].get("sentry:option-epoch") ) data = super().serialize(obj, attrs, user) data.update( { "latestRelease": attrs["latest_release"], "options": { "sentry:csp_ignored_sources_defaults": bool( attrs["options"].get("sentry:csp_ignored_sources_defaults", True) ), "sentry:csp_ignored_sources": "\n".join( attrs["options"].get("sentry:csp_ignored_sources", []) or [] ), "sentry:reprocessing_active": bool( attrs["options"].get("sentry:reprocessing_active", False) ), "filters:blacklisted_ips": "\n".join( attrs["options"].get("sentry:blacklisted_ips", []) ), f"filters:{FilterTypes.RELEASES}": "\n".join( attrs["options"].get(f"sentry:{FilterTypes.RELEASES}", []) ), f"filters:{FilterTypes.ERROR_MESSAGES}": "\n".join( attrs["options"].get(f"sentry:{FilterTypes.ERROR_MESSAGES}", []) ), "feedback:branding": attrs["options"].get("feedback:branding", "1") == "1", }, "digestsMinDelay": attrs["options"].get( "digests:mail:minimum_delay", digests.minimum_delay ), "digestsMaxDelay": attrs["options"].get( "digests:mail:maximum_delay", digests.maximum_delay ), "subjectPrefix": attrs["options"].get( "mail:subject_prefix", options.get("mail.subject-prefix") ), "allowedDomains": attrs["options"].get("sentry:origins", ["*"]), "resolveAge": int(attrs["options"].get("sentry:resolve_age", 0)), "dataScrubber": bool(attrs["options"].get("sentry:scrub_data", True)), "dataScrubberDefaults": bool(attrs["options"].get("sentry:scrub_defaults", True)), "safeFields": attrs["options"].get("sentry:safe_fields", []), "storeCrashReports": convert_crashreport_count( attrs["options"].get("sentry:store_crash_reports"), allow_none=True ), "sensitiveFields": attrs["options"].get("sentry:sensitive_fields", []), "subjectTemplate": attrs["options"].get("mail:subject_template") or DEFAULT_SUBJECT_TEMPLATE.template, "securityToken": attrs["options"].get("sentry:token") or obj.get_security_token(), "securityTokenHeader": attrs["options"].get("sentry:token_header"), "verifySSL": bool(attrs["options"].get("sentry:verify_ssl", False)), "scrubIPAddresses": bool(attrs["options"].get("sentry:scrub_ip_address", False)), "scrapeJavaScript": bool(attrs["options"].get("sentry:scrape_javascript", True)), "groupingConfig": get_value_with_default("sentry:grouping_config"), "groupingEnhancements": get_value_with_default("sentry:grouping_enhancements"), "groupingEnhancementsBase": get_value_with_default( "sentry:grouping_enhancements_base" ), "secondaryGroupingExpiry": get_value_with_default( "sentry:secondary_grouping_expiry" ), "secondaryGroupingConfig": get_value_with_default( "sentry:secondary_grouping_config" ), "fingerprintingRules": get_value_with_default("sentry:fingerprinting_rules"), "organization": attrs["org"], "plugins": serialize( [ plugin for plugin in plugins.configurable_for_project(obj, version=None) if plugin.has_project_conf() ], user, PluginSerializer(obj), ), "platforms": attrs["platforms"], "processingIssues": attrs["processing_issues"], "defaultEnvironment": attrs["options"].get("sentry:default_environment"), "relayPiiConfig": attrs["options"].get("sentry:relay_pii_config"), "builtinSymbolSources": get_value_with_default("sentry:builtin_symbol_sources"), "dynamicSampling": get_value_with_default("sentry:dynamic_sampling"), "eventProcessing": { "symbolicationDegraded": False, }, } ) custom_symbol_sources_json = attrs["options"].get("sentry:symbol_sources") try: sources = parse_sources(custom_symbol_sources_json, False) except Exception: # In theory sources stored on the project should be valid. If they are invalid, we don't # want to abort serialization just for sources, so just return an empty list instead of # returning sources with their secrets included. serialized_sources = "[]" else: redacted_sources = redact_source_secrets(sources) serialized_sources = json.dumps(redacted_sources) data.update( { "symbolSources": serialized_sources, } ) return data