Example #1
0
    def test_project(self):
        project = Project.objects.get()
        ProjectOption.objects.create(project=project, key='sentry:origins', value=['http://foo.example'])

        with self.Settings(SENTRY_ALLOW_ORIGIN=None):
            result = get_origins(project)
            self.assertEquals(result, frozenset(['http://foo.example']))
Example #2
0
    def test_empty_origin_values(self):
        project = Project.objects.get()
        project.update_option('sentry:origins', [u'*', None, ''])

        with self.settings(SENTRY_ALLOW_ORIGIN=None):
            result = get_origins(project)
            self.assertEquals(result, frozenset([u'*']))
Example #3
0
    def test_project_and_setting(self):
        project = Project.objects.get()
        project.update_option('sentry:origins', ['http://foo.example'])

        with self.settings(SENTRY_ALLOW_ORIGIN='http://example.com'):
            result = get_origins(project)
            self.assertEquals(result, frozenset(['http://foo.example', 'http://example.com']))
Example #4
0
    def test_project_and_setting(self):
        from sentry.models import Project, ProjectOption
        project = Project.objects.get()
        ProjectOption.objects.create(project=project, key='sentry:origins', value=['http://foo.example'])

        with self.Settings(SENTRY_ALLOW_ORIGIN='http://example.com'):
            result = get_origins(project)
            self.assertEquals(result, frozenset(['http://foo.example', 'http://example.com']))
Example #5
0
def crossdomain_xml(request, project):
    origin_list = get_origins(project)
    if origin_list == '*':
        origin_list = [origin_list]

    response = render_to_response('sentry/crossdomain.xml', {
        'origin_list': origin_list
    }, request)
    response['Content-Type'] = 'application/xml'

    return response
Example #6
0
def crossdomain_xml(request, project_id):
    if not project_id.isdigit():
        return HttpResponse(status=404)

    try:
        project = Project.objects.get_from_cache(id=project_id)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    response = render_to_response("sentry/crossdomain.xml", {"origin_list": origin_list})
    response["Content-Type"] = "application/xml"

    return response
Example #7
0
def crossdomain_xml(request, project_id):
    if not project_id.isdigit():
        return HttpResponse(status=404)

    try:
        project = Project.objects.get_from_cache(id=project_id)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    response = render_to_response('sentry/crossdomain.xml',
                                  {'origin_list': origin_list})
    response['Content-Type'] = 'application/xml'

    return response
Example #8
0
File: api.py Project: rnoldo/sentry
def crossdomain_xml(request, project_id):
    if project_id.isdigit():
        lookup = {"id": project_id}
    else:
        lookup = {"slug": project_id}
    try:
        project = Project.objects.get_from_cache(**lookup)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    if origin_list == "*":
        origin_list = [origin_list]

    response = render_to_response("sentry/crossdomain.xml", {"origin_list": origin_list})
    response["Content-Type"] = "application/xml"

    return response
Example #9
0
def crossdomain_xml(request, project_id):
    if project_id.isdigit():
        lookup = {'id': project_id}
    else:
        lookup = {'slug': project_id}
    try:
        project = Project.objects.get_from_cache(**lookup)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    if origin_list == '*':
        origin_list = [origin_list]

    response = render_to_response('sentry/crossdomain.xml',
                                  {'origin_list': origin_list})
    response['Content-Type'] = 'application/xml'

    return response
Example #10
0
def crossdomain_xml(request, project_id):
    if not project_id.isdigit():
        return HttpResponse(status=404)

    try:
        project = Project.objects.get_from_cache(id=project_id)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    if origin_list == ['*']:
        origin_list = [origin_list]

    response = render_to_response('sentry/crossdomain.xml', {
        'origin_list': origin_list
    })
    response['Content-Type'] = 'application/xml'

    return response
Example #11
0
def crossdomain_xml(request, project_id):
    if project_id.isdigit():
        lookup = {'id': project_id}
    else:
        lookup = {'slug': project_id}
    try:
        project = Project.objects.get_from_cache(**lookup)
    except Project.DoesNotExist:
        return HttpResponse(status=404)

    origin_list = get_origins(project)
    if origin_list == '*':
        origin_list = [origin_list]

    response = render_to_response('sentry/crossdomain.xml', {
        'origin_list': origin_list
    })
    response['Content-Type'] = 'application/xml'

    return response
Example #12
0
 def get_allowed_origins(self):
     from sentry.utils.http import get_origins
     return get_origins(self.project)
Example #13
0
 def test_setting_uri(self):
     with self.settings(SENTRY_ALLOW_ORIGIN='http://example.com'):
         result = get_origins(None)
         self.assertEquals(result, frozenset(['http://example.com']))
Example #14
0
 def test_setting_all(self):
     with self.settings(SENTRY_ALLOW_ORIGIN='*'):
         result = get_origins(None)
         self.assertEquals(result, frozenset(['*']))
Example #15
0
 def test_setting_empty(self):
     with self.settings(SENTRY_ALLOW_ORIGIN=None):
         result = get_origins(None)
         self.assertEquals(result, frozenset([]))
Example #16
0
def get_project_config(project,
                       org_options=None,
                       full_config=True,
                       project_keys=None):
    """
    Constructs the ProjectConfig information.

    :param project: The project to load configuration for. Ensure that
        organization is bound on this object; otherwise it will be loaded from
        the database.
    :param org_options: Inject preloaded organization options for faster loading.
        If ``None``, options are lazy-loaded from the database.
    :param full_config: True if only the full config is required, False
        if only the restricted (for external relays) is required
        (default True, i.e. full configuration)
    :param project_keys: Pre-fetched project keys for performance, similar to
        org_options. However, if no project keys are provided it is assumed
        that the config does not need to contain auth information (this is the
        case when used in python's StoreView)

    :return: a ProjectConfig object for the given project
    """
    with configure_scope() as scope:
        scope.set_tag("project", project.id)

    public_keys = []

    for project_key in project_keys or ():
        key = {
            "publicKey": project_key.public_key,
            "isEnabled": project_key.status == 0
        }
        if full_config:
            key["numericId"] = project_key.id

            key["quotas"] = [
                quota.to_json()
                for quota in quotas.get_quotas(project, key=project_key)
            ]
        public_keys.append(key)

    now = datetime.utcnow().replace(tzinfo=utc)

    if org_options is None:
        org_options = OrganizationOption.objects.get_all_values(
            project.organization_id)

    with Hub.current.start_span(op="get_public_config"):

        cfg = {
            "disabled": project.status > 0,
            "slug": project.slug,
            "lastFetch": now,
            "lastChange": project.get_option("sentry:relay-rev-lastchange",
                                             now),
            "rev": project.get_option("sentry:relay-rev",
                                      uuid.uuid4().hex),
            "publicKeys": public_keys,
            "config": {
                "allowedDomains":
                list(get_origins(project)),
                "trustedRelays":
                org_options.get("sentry:trusted-relays", []),
                "piiConfig":
                _get_pii_config(project),
                "datascrubbingSettings":
                _get_datascrubbing_settings(project, org_options),
            },
            "projectId": project.id,
        }

    if not full_config:
        # This is all we need for external Relay processors
        return ProjectConfig(project, **cfg)

    # The organization id is only required for reporting when processing events
    # internally. Do not expose it to external Relays.
    cfg["organizationId"] = project.organization_id

    project_cfg = cfg["config"]

    with Hub.current.start_span(op="get_filter_settings"):
        # get the filter settings for this project
        filter_settings = {}
        project_cfg["filterSettings"] = filter_settings

        for flt in get_all_filters():
            filter_id = get_filter_key(flt)
            settings = _load_filter_settings(flt, project)
            filter_settings[filter_id] = settings

        invalid_releases = project.get_option(u"sentry:{}".format(
            FilterTypes.RELEASES))
        if invalid_releases:
            filter_settings["releases"] = {"releases": invalid_releases}

        blacklisted_ips = project.get_option("sentry:blacklisted_ips")
        if blacklisted_ips:
            filter_settings["clientIps"] = {"blacklistedIps": blacklisted_ips}

        error_messages = project.get_option(u"sentry:{}".format(
            FilterTypes.ERROR_MESSAGES))
        if error_messages:
            filter_settings["errorMessages"] = {"patterns": error_messages}

        csp_disallowed_sources = []
        if bool(project.get_option("sentry:csp_ignored_sources_defaults",
                                   True)):
            csp_disallowed_sources += DEFAULT_DISALLOWED_SOURCES
        csp_disallowed_sources += project.get_option(
            "sentry:csp_ignored_sources", [])
        if csp_disallowed_sources:
            filter_settings["csp"] = {
                "disallowedSources": csp_disallowed_sources
            }

    with Hub.current.start_span(op="get_grouping_config_dict_for_project"):
        project_cfg["groupingConfig"] = get_grouping_config_dict_for_project(
            project)

    return ProjectConfig(project, **cfg)
Example #17
0
    def test_project_default(self):
        project = Project.objects.get()

        with self.settings(SENTRY_ALLOW_ORIGIN=None):
            result = get_origins(project)
            self.assertEquals(result, frozenset(['*']))
Example #18
0
def get_project_config(project, full_config=True, project_keys=None):
    """
    Constructs the ProjectConfig information.

    :param project: The project to load configuration for. Ensure that
        organization is bound on this object; otherwise it will be loaded from
        the database.
    :param full_config: True if only the full config is required, False
        if only the restricted (for external relays) is required
        (default True, i.e. full configuration)
    :param project_keys: Pre-fetched project keys for performance. However, if
        no project keys are provided it is assumed that the config does not
        need to contain auth information (this is the case when used in
        python's StoreView)

    :return: a ProjectConfig object for the given project
    """
    with configure_scope() as scope:
        scope.set_tag("project", project.id)

    if project.status != ObjectStatus.VISIBLE:
        return ProjectConfig(project, disabled=True)

    public_keys = get_public_key_configs(project,
                                         full_config,
                                         project_keys=project_keys)

    with Hub.current.start_span(op="get_public_config"):
        now = datetime.utcnow().replace(tzinfo=utc)
        cfg = {
            "disabled": False,
            "slug": project.slug,
            "lastFetch": now,
            "lastChange": project.get_option("sentry:relay-rev-lastchange",
                                             now),
            "rev": project.get_option("sentry:relay-rev",
                                      uuid.uuid4().hex),
            "publicKeys": public_keys,
            "config": {
                "allowedDomains":
                list(get_origins(project)),
                "trustedRelays": [
                    r["public_key"] for r in project.organization.get_option(
                        "sentry:trusted-relays", []) if r
                ],
                "piiConfig":
                get_pii_config(project),
                "datascrubbingSettings":
                get_datascrubbing_settings(project),
            },
            "organizationId": project.organization_id,
            "projectId":
            project.id,  # XXX: Unused by Relay, required by Python store
        }

    if not full_config:
        # This is all we need for external Relay processors
        return ProjectConfig(project, **cfg)

    with Hub.current.start_span(op="get_filter_settings"):
        cfg["config"]["filterSettings"] = get_filter_settings(project)
    with Hub.current.start_span(op="get_grouping_config_dict_for_project"):
        cfg["config"]["groupingConfig"] = get_grouping_config_dict_for_project(
            project)
    with Hub.current.start_span(op="get_event_retention"):
        cfg["config"]["eventRetention"] = quotas.get_event_retention(
            project.organization)
    with Hub.current.start_span(op="get_all_quotas"):
        cfg["config"]["quotas"] = get_quotas(project, keys=project_keys)

    return ProjectConfig(project, **cfg)
Example #19
0
 def get_allowed_origins(self):
     from sentry.utils.http import get_origins
     return get_origins(self.project)
Example #20
0
def get_project_config(project_id, full_config=True, for_store=False):
    """
    Constructs the ProjectConfig information.

    :param project_id: the project id as int or string
    :param full_config: True if only the full config is required, False
        if only the restricted (for external relays) is required
        (default True, i.e. full configuration)
    :param for_store: If set to true, this omits all parameters that are not
        needed for store normalization. This is a temporary flag that should
        be removed once store has been moved to Relay. Most importantly, this
        avoids database accesses.

    :return: a ProjectConfig object for the given project
    """
    project = _get_project_from_id(six.text_type(project_id))

    if project is None:
        raise APIError("Invalid project id:{}".format(project_id))

    with configure_scope() as scope:
        scope.set_tag("project", project.id)

    if for_store:
        project_keys = []
    else:
        project_keys = ProjectKey.objects.filter(project=project).all()

    public_keys = {}
    for project_key in project_keys:
        public_keys[project_key.public_key] = project_key.status == 0

    now = datetime.utcnow().replace(tzinfo=utc)

    org_options = OrganizationOption.objects.get_all_values(
        project.organization_id)

    cfg = {
        "disabled": project.status > 0,
        "slug": project.slug,
        "lastFetch": now,
        "lastChange": project.get_option("sentry:relay-rev-lastchange", now),
        "rev": project.get_option("sentry:relay-rev",
                                  uuid.uuid4().hex),
        "publicKeys": public_keys,
        "config": {
            "allowedDomains":
            project.get_option("sentry:origins", ["*"]),
            "trustedRelays":
            org_options.get("sentry:trusted-relays", []),
            "piiConfig":
            _get_pii_config(project),
            "datascrubbingSettings":
            _get_datascrubbing_settings(project, org_options),
        },
        "project_id": project.id,
    }

    if not full_config:
        # This is all we need for external Relay processors
        return ProjectConfig(project, **cfg)

    # The organization id is only required for reporting when processing events
    # internally. Do not expose it to external Relays.
    cfg["organization_id"] = project.organization_id

    # Explicitly bind Organization so we don't implicitly query it later
    # this just allows us to comfortably assure that `project.organization` is safe.
    # This also allows us to pull the object from cache, instead of being
    # implicitly fetched from database.
    project.organization = Organization.objects.get_from_cache(
        id=project.organization_id)

    if project.organization is not None:
        org_options = OrganizationOption.objects.get_all_values(
            project.organization_id)
    else:
        org_options = {}

    project_cfg = cfg["config"]

    # get the filter settings for this project
    filter_settings = {}
    project_cfg["filter_settings"] = filter_settings

    for flt in get_all_filters():
        filter_id = get_filter_key(flt)
        settings = _load_filter_settings(flt, project)
        filter_settings[filter_id] = settings

    invalid_releases = project.get_option(u"sentry:{}".format(
        FilterTypes.RELEASES))
    if invalid_releases:
        filter_settings[FilterTypes.RELEASES] = {"releases": invalid_releases}

    blacklisted_ips = project.get_option("sentry:blacklisted_ips")
    if blacklisted_ips:
        filter_settings["client_ips"] = {"blacklisted_ips": blacklisted_ips}

    error_messages = project.get_option(u"sentry:{}".format(
        FilterTypes.ERROR_MESSAGES))
    if error_messages:
        filter_settings[FilterTypes.ERROR_MESSAGES] = {
            "patterns": error_messages
        }

    csp_disallowed_sources = []
    if bool(project.get_option("sentry:csp_ignored_sources_defaults", True)):
        csp_disallowed_sources += DEFAULT_DISALLOWED_SOURCES
    csp_disallowed_sources += project.get_option("sentry:csp_ignored_sources",
                                                 [])
    if csp_disallowed_sources:
        filter_settings["csp"] = {"disallowed_sources": csp_disallowed_sources}

    scrub_ip_address = org_options.get("sentry:require_scrub_ip_address",
                                       False) or project.get_option(
                                           "sentry:scrub_ip_address", False)

    project_cfg["scrub_ip_addresses"] = scrub_ip_address

    project_cfg["grouping_config"] = get_grouping_config_dict_for_project(
        project)
    project_cfg["allowed_domains"] = list(get_origins(project))

    return ProjectConfig(project, **cfg)
Example #21
0
def get_full_relay_config(project_id):
    """
    Constructs the internal (big) RelayConfig

    :param project_id: the project id as int or string
    :return: FullRelayConfig the relay configuration
    """

    cfg = {}
    project = _get_project_from_id(six.text_type(project_id))

    if project is None:
        raise APIError("Invalid project id:{}".format(project_id))

    cfg['project_id'] = project.id
    cfg['organization_id'] = project.organization_id

    # Explicitly bind Organization so we don't implicitly query it later
    # this just allows us to comfortably assure that `project.organization` is safe.
    # This also allows us to pull the object from cache, instead of being
    # implicitly fetched from database.
    project.organization = Organization.objects.get_from_cache(
        id=project.organization_id)

    if project.organization is not None:
        org_options = OrganizationOption.objects.get_all_values(
            project.organization_id)
    else:
        org_options = {}

    # get the project options
    project_cfg = {}
    cfg['config'] = project_cfg

    # getting kafka info
    try:
        project_cfg['kafka_max_event_size'] = options.get(
            'kafka-publisher.max-event-size')
        project_cfg['kafka_raw_event_sample_rate'] = options.get(
            'kafka-publisher.raw-event-sample-rate')
    except Exception:
        pass  # should we log ?

    invalid_releases = project.get_option(u'sentry:{}'.format(
        FilterTypes.RELEASES))
    if invalid_releases is not None:
        project_cfg['invalid_releases'] = invalid_releases

    # get the filters enabled for the current project
    enabled_filters = [
        filter_class.id for filter_class in filters.all()
        if filter_class(project).is_enabled()
    ]

    project_cfg['enabled_filters'] = enabled_filters

    scrub_ip_address = (
        org_options.get('sentry:require_scrub_ip_address', False)
        or project.get_option('sentry:scrub_ip_address', False))

    project_cfg['scrub_ip_addresses'] = scrub_ip_address

    scrub_data = (org_options.get('sentry:require_scrub_data', False)
                  or project.get_option('sentry:scrub_data', True))

    project_cfg['scrub_data'] = scrub_data
    project_cfg['grouping_config'] = get_grouping_config_dict_for_project(
        project)
    project_cfg['allowed_domains'] = list(get_origins(project))

    if scrub_data:
        # We filter data immediately before it ever gets into the queue
        sensitive_fields_key = 'sentry:sensitive_fields'
        sensitive_fields = (org_options.get(sensitive_fields_key, []) +
                            project.get_option(sensitive_fields_key, []))
        project_cfg['sensitive_fields'] = sensitive_fields

        exclude_fields_key = 'sentry:safe_fields'
        exclude_fields = (org_options.get(exclude_fields_key, []) +
                          project.get_option(exclude_fields_key, []))
        project_cfg['exclude_fields'] = exclude_fields

        scrub_defaults = (org_options.get('sentry:require_scrub_defaults',
                                          False)
                          or project.get_option('sentry:scrub_defaults', True))
        project_cfg['scrub_defaults'] = scrub_defaults

    return FullRelayConfig(project, **cfg)
Example #22
0
def get_project_config(project,
                       org_options=None,
                       full_config=True,
                       for_store=False):
    """
    Constructs the ProjectConfig information.

    :param project: The project to load configuration for. Ensure that
        organization is bound on this object; otherwise it will be loaded from
        the database.
    :param org_options: Inject preloaded organization options for faster loading.
        If ``None``, options are lazy-loaded from the database.
    :param full_config: True if only the full config is required, False
        if only the restricted (for external relays) is required
        (default True, i.e. full configuration)
    :param for_store: If set to true, this omits all parameters that are not
        needed for Relay. This is a temporary flag that should be removed once
        store has been moved to Relay. Most importantly, this avoids database
        accesses.

    :return: a ProjectConfig object for the given project
    """
    with configure_scope() as scope:
        scope.set_tag("project", project.id)

    if for_store:
        project_keys = []
    else:
        project_keys = ProjectKey.objects.filter(project=project).all()

    public_keys = []

    for project_key in project_keys:
        key = {
            "publicKey": project_key.public_key,
            "isEnabled": project_key.status == 0
        }
        if full_config:
            key["numericId"] = project_key.id

            key["quotas"] = [
                quota.to_json()
                for quota in quotas.get_quotas(project, key=project_key)
            ]
        public_keys.append(key)

    now = datetime.utcnow().replace(tzinfo=utc)

    if org_options is None:
        org_options = OrganizationOption.objects.get_all_values(
            project.organization_id)

    cfg = {
        "disabled": project.status > 0,
        "slug": project.slug,
        "lastFetch": now,
        "lastChange": project.get_option("sentry:relay-rev-lastchange", now),
        "rev": project.get_option("sentry:relay-rev",
                                  uuid.uuid4().hex),
        "publicKeys": public_keys,
        "config": {
            "allowedDomains":
            project.get_option("sentry:origins", ["*"]),
            "trustedRelays":
            org_options.get("sentry:trusted-relays", []),
            "piiConfig":
            _get_pii_config(project),
            "datascrubbingSettings":
            _get_datascrubbing_settings(project, org_options),
        },
        "project_id": project.id,
    }

    if not full_config:
        # This is all we need for external Relay processors
        return ProjectConfig(project, **cfg)

    # The organization id is only required for reporting when processing events
    # internally. Do not expose it to external Relays.
    cfg["organization_id"] = project.organization_id

    project_cfg = cfg["config"]

    # get the filter settings for this project
    filter_settings = {}
    project_cfg["filter_settings"] = filter_settings

    for flt in get_all_filters():
        filter_id = get_filter_key(flt)
        settings = _load_filter_settings(flt, project)
        filter_settings[filter_id] = settings

    invalid_releases = project.get_option(u"sentry:{}".format(
        FilterTypes.RELEASES))
    if invalid_releases:
        filter_settings[FilterTypes.RELEASES] = {"releases": invalid_releases}

    blacklisted_ips = project.get_option("sentry:blacklisted_ips")
    if blacklisted_ips:
        filter_settings["client_ips"] = {"blacklisted_ips": blacklisted_ips}

    error_messages = project.get_option(u"sentry:{}".format(
        FilterTypes.ERROR_MESSAGES))
    if error_messages:
        filter_settings[FilterTypes.ERROR_MESSAGES] = {
            "patterns": error_messages
        }

    csp_disallowed_sources = []
    if bool(project.get_option("sentry:csp_ignored_sources_defaults", True)):
        csp_disallowed_sources += DEFAULT_DISALLOWED_SOURCES
    csp_disallowed_sources += project.get_option("sentry:csp_ignored_sources",
                                                 [])
    if csp_disallowed_sources:
        filter_settings["csp"] = {"disallowed_sources": csp_disallowed_sources}

    scrub_ip_address = org_options.get("sentry:require_scrub_ip_address",
                                       False) or project.get_option(
                                           "sentry:scrub_ip_address", False)

    project_cfg["scrub_ip_addresses"] = scrub_ip_address

    project_cfg["grouping_config"] = get_grouping_config_dict_for_project(
        project)
    project_cfg["allowed_domains"] = list(get_origins(project))

    return ProjectConfig(project, **cfg)
Example #23
0
def get_project_config(project_id, full_config=True, for_store=False):
    """
    Constructs the ProjectConfig information.

    :param project_id: the project id as int or string
    :param full_config: True if only the full config is required, False
        if only the restricted (for external relays) is required
        (default True, i.e. full configuration)
    :param for_store: If set to true, this omits all parameters that are not
        needed for store normalization. This is a temporary flag that should
        be removed once store has been moved to Relay. Most importantly, this
        avoids database accesses.

    :return: a ProjectConfig object for the given project
    """
    project = _get_project_from_id(six.text_type(project_id))

    if project is None:
        raise APIError("Invalid project id:{}".format(project_id))

    with configure_scope() as scope:
        scope.set_tag("project", project.id)

    if for_store:
        project_keys = []
    else:
        project_keys = ProjectKey.objects \
            .filter(project=project) \
            .all()

    public_keys = {}
    for project_key in project_keys:
        public_keys[project_key.public_key] = project_key.status == 0

    now = datetime.utcnow().replace(tzinfo=utc)

    org_options = OrganizationOption.objects.get_all_values(
        project.organization_id)

    cfg = {
        'disabled': project.status > 0,
        'slug': project.slug,
        'lastFetch': now,
        'lastChange': project.get_option('sentry:relay-rev-lastchange', now),
        'rev': project.get_option('sentry:relay-rev', uuid.uuid4().hex),
        'publicKeys': public_keys,
        'config': {
            'allowedDomains': project.get_option('sentry:origins', ['*']),
            'trustedRelays': org_options.get('sentry:trusted-relays', []),
            'piiConfig': _get_pii_config(project, org_options),
        },
        'project_id': project.id,
    }

    if not full_config:
        # This is all we need for external Relay processors
        return ProjectConfig(project, **cfg)

    # The organization id is only required for reporting when processing events
    # internally. Do not expose it to external Relays.
    cfg['organization_id'] = project.organization_id

    # Explicitly bind Organization so we don't implicitly query it later
    # this just allows us to comfortably assure that `project.organization` is safe.
    # This also allows us to pull the object from cache, instead of being
    # implicitly fetched from database.
    project.organization = Organization.objects.get_from_cache(
        id=project.organization_id)

    if project.organization is not None:
        org_options = OrganizationOption.objects.get_all_values(
            project.organization_id)
    else:
        org_options = {}

    project_cfg = cfg['config']

    # get the filter settings for this project
    filter_settings = {}
    project_cfg['filter_settings'] = filter_settings

    for flt in get_all_filters():
        filter_id = get_filter_key(flt)
        settings = _load_filter_settings(flt, project)
        filter_settings[filter_id] = settings

    invalid_releases = project.get_option(u'sentry:{}'.format(FilterTypes.RELEASES))
    if invalid_releases:
        filter_settings[FilterTypes.RELEASES] = {'releases': invalid_releases}

    blacklisted_ips = project.get_option('sentry:blacklisted_ips')
    if blacklisted_ips:
        filter_settings['client_ips'] = {'blacklisted_ips': blacklisted_ips}

    error_messages = project.get_option(u'sentry:{}'.format(FilterTypes.ERROR_MESSAGES))
    if error_messages:
        filter_settings[FilterTypes.ERROR_MESSAGES] = {'patterns': error_messages}

    csp_disallowed_sources = []
    if bool(project.get_option('sentry:csp_ignored_sources_defaults', True)):
        csp_disallowed_sources += DEFAULT_DISALLOWED_SOURCES
    csp_disallowed_sources += project.get_option('sentry:csp_ignored_sources', [])
    if csp_disallowed_sources:
        filter_settings['csp'] = {'disallowed_sources': csp_disallowed_sources}

    scrub_ip_address = (org_options.get('sentry:require_scrub_ip_address', False) or
                        project.get_option('sentry:scrub_ip_address', False))

    project_cfg['scrub_ip_addresses'] = scrub_ip_address

    scrub_data = (org_options.get('sentry:require_scrub_data', False) or
                  project.get_option('sentry:scrub_data', True))

    project_cfg['scrub_data'] = scrub_data
    project_cfg['grouping_config'] = get_grouping_config_dict_for_project(project)
    project_cfg['allowed_domains'] = list(get_origins(project))

    if scrub_data:
        # We filter data immediately before it ever gets into the queue
        sensitive_fields_key = 'sentry:sensitive_fields'
        sensitive_fields = (
            org_options.get(sensitive_fields_key, []) +
            project.get_option(sensitive_fields_key, [])
        )
        project_cfg['sensitive_fields'] = sensitive_fields

        exclude_fields_key = 'sentry:safe_fields'
        exclude_fields = (
            org_options.get(exclude_fields_key, []) +
            project.get_option(exclude_fields_key, [])
        )
        project_cfg['exclude_fields'] = exclude_fields

        scrub_defaults = (org_options.get('sentry:require_scrub_defaults', False) or
                          project.get_option('sentry:scrub_defaults', True))
        project_cfg['scrub_defaults'] = scrub_defaults

    return ProjectConfig(project, **cfg)