コード例 #1
0
ファイル: event_manager.py プロジェクト: longzitianya/sentry
def get_max_crashreports(model):
    value = model.get_option("sentry:store_crash_reports")
    return convert_crashreport_count(value)
コード例 #2
0
    def put(self, request: Request, project) -> Response:
        """
        Update a Project
        ````````````````

        Update various attributes and configurable settings for the given
        project.  Only supplied values are updated.

        :pparam string organization_slug: the slug of the organization the
                                          project belongs to.
        :pparam string project_slug: the slug of the project to update.
        :param string name: the new name for the project.
        :param string slug: the new slug for the project.
        :param string team: the slug of new team for the project. Note, will be deprecated
                            soon when multiple teams can have access to a project.
        :param string platform: the new platform for the project.
        :param boolean isBookmarked: in case this API call is invoked with a
                                     user context this allows changing of
                                     the bookmark flag.
        :param int digestsMinDelay:
        :param int digestsMaxDelay:
        :auth: required
        """
        has_project_write = (request.auth and request.auth.has_scope("project:write")) or (
            request.access and request.access.has_scope("project:write")
        )

        changed_proj_settings = {}

        if has_project_write:
            serializer_cls = ProjectAdminSerializer
        else:
            serializer_cls = ProjectMemberSerializer

        serializer = serializer_cls(
            data=request.data, partial=True, context={"project": project, "request": request}
        )
        if not serializer.is_valid():
            return Response(serializer.errors, status=400)

        result = serializer.validated_data

        allow_dynamic_sampling = features.has(
            "organizations:filters-and-sampling", project.organization, actor=request.user
        )

        allow_dynamic_sampling_error_rules = features.has(
            "organizations:filters-and-sampling-error-rules",
            project.organization,
            actor=request.user,
        )

        if not allow_dynamic_sampling and result.get("dynamicSampling"):
            # trying to set dynamic sampling with feature disabled
            return Response(
                {"detail": ["You do not have permission to set dynamic sampling."]},
                status=403,
            )

        if not has_project_write:
            # options isn't part of the serializer, but should not be editable by members
            for key in chain(ProjectAdminSerializer().fields.keys(), ["options"]):
                if request.data.get(key) and not result.get(key):
                    return Response(
                        {"detail": ["You do not have permission to perform this action."]},
                        status=403,
                    )

        changed = False

        old_slug = None
        if result.get("slug"):
            old_slug = project.slug
            project.slug = result["slug"]
            changed = True
            changed_proj_settings["new_slug"] = project.slug
            changed_proj_settings["old_slug"] = old_slug

        if result.get("name"):
            project.name = result["name"]
            changed = True
            changed_proj_settings["new_project"] = project.name

        old_team_id = None
        new_team = None
        if result.get("team"):
            return Response(
                {"detail": ["Editing a team via this endpoint has been deprecated."]}, status=400
            )

        if result.get("platform"):
            project.platform = result["platform"]
            changed = True

        if changed:
            project.save()
            if old_team_id is not None:
                ProjectTeam.objects.filter(project=project, team_id=old_team_id).update(
                    team=new_team
                )

            if old_slug:
                ProjectRedirect.record(project, old_slug)

        if result.get("isBookmarked"):
            try:
                with transaction.atomic():
                    ProjectBookmark.objects.create(project_id=project.id, user=request.user)
            except IntegrityError:
                pass
        elif result.get("isBookmarked") is False:
            ProjectBookmark.objects.filter(project_id=project.id, user=request.user).delete()

        if result.get("digestsMinDelay"):
            project.update_option("digests:mail:minimum_delay", result["digestsMinDelay"])
        if result.get("digestsMaxDelay"):
            project.update_option("digests:mail:maximum_delay", result["digestsMaxDelay"])
        if result.get("subjectPrefix") is not None:
            if project.update_option("mail:subject_prefix", result["subjectPrefix"]):
                changed_proj_settings["mail:subject_prefix"] = result["subjectPrefix"]
        if result.get("subjectTemplate"):
            project.update_option("mail:subject_template", result["subjectTemplate"])
        if result.get("scrubIPAddresses") is not None:
            if project.update_option("sentry:scrub_ip_address", result["scrubIPAddresses"]):
                changed_proj_settings["sentry:scrub_ip_address"] = result["scrubIPAddresses"]
        if result.get("groupingConfig") is not None:
            if project.update_option("sentry:grouping_config", result["groupingConfig"]):
                changed_proj_settings["sentry:grouping_config"] = result["groupingConfig"]
        if result.get("groupingEnhancements") is not None:
            if project.update_option(
                "sentry:grouping_enhancements", result["groupingEnhancements"]
            ):
                changed_proj_settings["sentry:grouping_enhancements"] = result[
                    "groupingEnhancements"
                ]
        if result.get("fingerprintingRules") is not None:
            if project.update_option("sentry:fingerprinting_rules", result["fingerprintingRules"]):
                changed_proj_settings["sentry:fingerprinting_rules"] = result["fingerprintingRules"]
        if result.get("secondaryGroupingConfig") is not None:
            if project.update_option(
                "sentry:secondary_grouping_config", result["secondaryGroupingConfig"]
            ):
                changed_proj_settings["sentry:secondary_grouping_config"] = result[
                    "secondaryGroupingConfig"
                ]

        if result.get("secondaryGroupingExpiry") is not None:
            if project.update_option(
                "sentry:secondary_grouping_expiry", result["secondaryGroupingExpiry"]
            ):
                changed_proj_settings["sentry:secondary_grouping_expiry"] = result[
                    "secondaryGroupingExpiry"
                ]
        if result.get("securityToken") is not None:
            if project.update_option("sentry:token", result["securityToken"]):
                changed_proj_settings["sentry:token"] = result["securityToken"]
        if result.get("securityTokenHeader") is not None:
            if project.update_option("sentry:token_header", result["securityTokenHeader"]):
                changed_proj_settings["sentry:token_header"] = result["securityTokenHeader"]
        if result.get("verifySSL") is not None:
            if project.update_option("sentry:verify_ssl", result["verifySSL"]):
                changed_proj_settings["sentry:verify_ssl"] = result["verifySSL"]
        if result.get("dataScrubber") is not None:
            if project.update_option("sentry:scrub_data", result["dataScrubber"]):
                changed_proj_settings["sentry:scrub_data"] = result["dataScrubber"]
        if result.get("dataScrubberDefaults") is not None:
            if project.update_option("sentry:scrub_defaults", result["dataScrubberDefaults"]):
                changed_proj_settings["sentry:scrub_defaults"] = result["dataScrubberDefaults"]
        if result.get("sensitiveFields") is not None:
            if project.update_option("sentry:sensitive_fields", result["sensitiveFields"]):
                changed_proj_settings["sentry:sensitive_fields"] = result["sensitiveFields"]
        if result.get("safeFields") is not None:
            if project.update_option("sentry:safe_fields", result["safeFields"]):
                changed_proj_settings["sentry:safe_fields"] = result["safeFields"]
        if "storeCrashReports" in result is not None:
            if project.get_option("sentry:store_crash_reports") != result["storeCrashReports"]:
                changed_proj_settings["sentry:store_crash_reports"] = result["storeCrashReports"]
                if result["storeCrashReports"] is None:
                    project.delete_option("sentry:store_crash_reports")
                else:
                    project.update_option("sentry:store_crash_reports", result["storeCrashReports"])
        if result.get("relayPiiConfig") is not None:
            if project.update_option("sentry:relay_pii_config", result["relayPiiConfig"]):
                changed_proj_settings["sentry:relay_pii_config"] = (
                    result["relayPiiConfig"].strip() or None
                )
        if result.get("builtinSymbolSources") is not None:
            if project.update_option(
                "sentry:builtin_symbol_sources", result["builtinSymbolSources"]
            ):
                changed_proj_settings["sentry:builtin_symbol_sources"] = result[
                    "builtinSymbolSources"
                ]
        if result.get("symbolSources") is not None:
            if project.update_option("sentry:symbol_sources", result["symbolSources"]):
                # Redact secrets so they don't get logged directly to the Audit Log
                sources_json = result["symbolSources"] or None
                try:
                    sources = parse_sources(sources_json)
                except Exception:
                    sources = []
                redacted_sources = redact_source_secrets(sources)
                changed_proj_settings["sentry:symbol_sources"] = redacted_sources
        if "defaultEnvironment" in result:
            if result["defaultEnvironment"] is None:
                project.delete_option("sentry:default_environment")
            else:
                project.update_option("sentry:default_environment", result["defaultEnvironment"])
        # resolveAge can be None
        if "resolveAge" in result:
            if project.update_option(
                "sentry:resolve_age",
                0 if result.get("resolveAge") is None else int(result["resolveAge"]),
            ):
                changed_proj_settings["sentry:resolve_age"] = result["resolveAge"]
        if result.get("scrapeJavaScript") is not None:
            if project.update_option("sentry:scrape_javascript", result["scrapeJavaScript"]):
                changed_proj_settings["sentry:scrape_javascript"] = result["scrapeJavaScript"]
        if result.get("allowedDomains"):
            if project.update_option("sentry:origins", result["allowedDomains"]):
                changed_proj_settings["sentry:origins"] = result["allowedDomains"]

        if "isSubscribed" in result:
            NotificationSetting.objects.update_settings(
                ExternalProviders.EMAIL,
                NotificationSettingTypes.ISSUE_ALERTS,
                get_option_value_from_boolean(result.get("isSubscribed")),
                user=request.user,
                project=project,
            )

        if "dynamicSampling" in result:
            raw_dynamic_sampling = result["dynamicSampling"]
            if (
                not allow_dynamic_sampling_error_rules
                and self._dynamic_sampling_contains_error_rule(raw_dynamic_sampling)
            ):
                return Response(
                    {
                        "detail": [
                            "Dynamic Sampling only accepts rules of type transaction or trace"
                        ]
                    },
                    status=400,
                )

            fixed_rules = self._fix_rule_ids(project, raw_dynamic_sampling)
            project.update_option("sentry:dynamic_sampling", fixed_rules)

        # TODO(dcramer): rewrite options to use standard API config
        if has_project_write:
            options = request.data.get("options", {})
            if "sentry:origins" in options:
                project.update_option(
                    "sentry:origins", clean_newline_inputs(options["sentry:origins"])
                )
            if "sentry:resolve_age" in options:
                project.update_option("sentry:resolve_age", int(options["sentry:resolve_age"]))
            if "sentry:scrub_data" in options:
                project.update_option("sentry:scrub_data", bool(options["sentry:scrub_data"]))
            if "sentry:scrub_defaults" in options:
                project.update_option(
                    "sentry:scrub_defaults", bool(options["sentry:scrub_defaults"])
                )
            if "sentry:safe_fields" in options:
                project.update_option(
                    "sentry:safe_fields", [s.strip().lower() for s in options["sentry:safe_fields"]]
                )
            if "sentry:store_crash_reports" in options:
                project.update_option(
                    "sentry:store_crash_reports",
                    convert_crashreport_count(
                        options["sentry:store_crash_reports"], allow_none=True
                    ),
                )
            if "sentry:relay_pii_config" in options:
                project.update_option(
                    "sentry:relay_pii_config", options["sentry:relay_pii_config"].strip() or None
                )
            if "sentry:sensitive_fields" in options:
                project.update_option(
                    "sentry:sensitive_fields",
                    [s.strip().lower() for s in options["sentry:sensitive_fields"]],
                )
            if "sentry:scrub_ip_address" in options:
                project.update_option(
                    "sentry:scrub_ip_address", bool(options["sentry:scrub_ip_address"])
                )
            if "sentry:grouping_config" in options:
                project.update_option("sentry:grouping_config", options["sentry:grouping_config"])
            if "sentry:fingerprinting_rules" in options:
                project.update_option(
                    "sentry:fingerprinting_rules", options["sentry:fingerprinting_rules"]
                )
            if "mail:subject_prefix" in options:
                project.update_option("mail:subject_prefix", options["mail:subject_prefix"])
            if "sentry:default_environment" in options:
                project.update_option(
                    "sentry:default_environment", options["sentry:default_environment"]
                )
            if "sentry:csp_ignored_sources_defaults" in options:
                project.update_option(
                    "sentry:csp_ignored_sources_defaults",
                    bool(options["sentry:csp_ignored_sources_defaults"]),
                )
            if "sentry:csp_ignored_sources" in options:
                project.update_option(
                    "sentry:csp_ignored_sources",
                    clean_newline_inputs(options["sentry:csp_ignored_sources"]),
                )
            if "sentry:blacklisted_ips" in options:
                project.update_option(
                    "sentry:blacklisted_ips",
                    clean_newline_inputs(options["sentry:blacklisted_ips"]),
                )
            if "feedback:branding" in options:
                project.update_option(
                    "feedback:branding", "1" if options["feedback:branding"] else "0"
                )
            if "sentry:reprocessing_active" in options:
                project.update_option(
                    "sentry:reprocessing_active", bool(options["sentry:reprocessing_active"])
                )
            if "filters:blacklisted_ips" in options:
                project.update_option(
                    "sentry:blacklisted_ips",
                    clean_newline_inputs(options["filters:blacklisted_ips"]),
                )
            if f"filters:{FilterTypes.RELEASES}" in options:
                if features.has("projects:custom-inbound-filters", project, actor=request.user):
                    project.update_option(
                        f"sentry:{FilterTypes.RELEASES}",
                        clean_newline_inputs(options[f"filters:{FilterTypes.RELEASES}"]),
                    )
                else:
                    return Response(
                        {"detail": ["You do not have that feature enabled"]}, status=400
                    )
            if f"filters:{FilterTypes.ERROR_MESSAGES}" in options:
                if features.has("projects:custom-inbound-filters", project, actor=request.user):
                    project.update_option(
                        f"sentry:{FilterTypes.ERROR_MESSAGES}",
                        clean_newline_inputs(
                            options[f"filters:{FilterTypes.ERROR_MESSAGES}"],
                            case_insensitive=False,
                        ),
                    )
                else:
                    return Response(
                        {"detail": ["You do not have that feature enabled"]}, status=400
                    )
            if "copy_from_project" in result:
                if not project.copy_settings_from(result["copy_from_project"]):
                    return Response({"detail": ["Copy project settings failed."]}, status=409)

            self.create_audit_entry(
                request=request,
                organization=project.organization,
                target_object=project.id,
                event=AuditLogEntryEvent.PROJECT_EDIT,
                data=changed_proj_settings,
            )

        data = serialize(project, request.user, DetailedProjectSerializer())
        return Response(data)
コード例 #3
0
    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"),
            "symbolSources":
            attrs["options"].get("sentry:symbol_sources"),
            "dynamicSampling":
            get_value_with_default("sentry:dynamic_sampling"),
            "breakdowns":
            get_value_with_default("sentry:breakdowns"),
        })
        return data
コード例 #4
0
    def serialize(self, obj, attrs, user, access):
        from sentry import experiments

        onboarding_tasks = list(
            OrganizationOnboardingTask.objects.filter(
                organization=obj).select_related("user"))

        experiment_assignments = experiments.all(org=obj, actor=user)

        context = super(DetailedOrganizationSerializer,
                        self).serialize(obj, attrs, user)
        max_rate = quotas.get_maximum_quota(obj)
        context["experiments"] = experiment_assignments
        context["quota"] = {
            "maxRate":
            max_rate[0],
            "maxRateInterval":
            max_rate[1],
            "accountLimit":
            int(
                OrganizationOption.objects.get_value(
                    organization=obj,
                    key="sentry:account-rate-limit",
                    default=ACCOUNT_RATE_LIMIT_DEFAULT,
                )),
            "projectLimit":
            int(
                OrganizationOption.objects.get_value(
                    organization=obj,
                    key="sentry:project-rate-limit",
                    default=PROJECT_RATE_LIMIT_DEFAULT,
                )),
        }

        context.update({
            "isDefault":
            obj.is_default,
            "defaultRole":
            obj.default_role,
            "availableRoles": [{
                "id": r.id,
                "name": r.name
            } for r in roles.get_all()],
            "openMembership":
            bool(obj.flags.allow_joinleave),
            "require2FA":
            bool(obj.flags.require_2fa),
            "allowSharedIssues":
            not obj.flags.disable_shared_issues,
            "enhancedPrivacy":
            bool(obj.flags.enhanced_privacy),
            "dataScrubber":
            bool(
                obj.get_option("sentry:require_scrub_data",
                               REQUIRE_SCRUB_DATA_DEFAULT)),
            "dataScrubberDefaults":
            bool(
                obj.get_option("sentry:require_scrub_defaults",
                               REQUIRE_SCRUB_DEFAULTS_DEFAULT)),
            "sensitiveFields":
            obj.get_option("sentry:sensitive_fields", SENSITIVE_FIELDS_DEFAULT)
            or [],
            "safeFields":
            obj.get_option("sentry:safe_fields", SAFE_FIELDS_DEFAULT) or [],
            "storeCrashReports":
            convert_crashreport_count(
                obj.get_option("sentry:store_crash_reports")),
            "attachmentsRole":
            six.text_type(
                obj.get_option("sentry:attachments_role",
                               ATTACHMENTS_ROLE_DEFAULT)),
            "debugFilesRole":
            six.text_type(
                obj.get_option("sentry:debug_files_role",
                               DEBUG_FILES_ROLE_DEFAULT)),
            "eventsMemberAdmin":
            bool(
                obj.get_option("sentry:events_member_admin",
                               EVENTS_MEMBER_ADMIN_DEFAULT)),
            "scrubIPAddresses":
            bool(
                obj.get_option("sentry:require_scrub_ip_address",
                               REQUIRE_SCRUB_IP_ADDRESS_DEFAULT)),
            "scrapeJavaScript":
            bool(
                obj.get_option("sentry:scrape_javascript",
                               SCRAPE_JAVASCRIPT_DEFAULT)),
            "allowJoinRequests":
            bool(obj.get_option("sentry:join_requests",
                                JOIN_REQUESTS_DEFAULT)),
            "relayPiiConfig":
            six.text_type(obj.get_option("sentry:relay_pii_config") or u"")
            or None,
            "apdexThreshold":
            int(
                obj.get_option("sentry:apdex_threshold",
                               APDEX_THRESHOLD_DEFAULT)),
        })

        trusted_relays_raw = obj.get_option("sentry:trusted-relays") or []
        # serialize trusted relays info into their external form
        context["trustedRelays"] = [
            TrustedRelaySerializer(raw).data for raw in trusted_relays_raw
        ]

        context["access"] = access.scopes
        if access.role is not None:
            context["role"] = access.role
        context[
            "pendingAccessRequests"] = OrganizationAccessRequest.objects.filter(
                team__organization=obj).count()
        context["onboardingTasks"] = serialize(onboarding_tasks, user,
                                               OnboardingTasksSerializer())
        return context
コード例 #5
0
ファイル: event_manager.py プロジェクト: rmr1154/sentry
def get_max_crashreports(model, allow_none=False):
    value = model.get_option("sentry:store_crash_reports")
    return convert_crashreport_count(value, allow_none=allow_none)