Repository: pypi/warehouse

Issue:
Implement a report URI for the Content Security Policy
In #93 a Content Security Policy was added, however reports are not being sent anywhere. Ideally they would go to something like Sentry (perhaps even sentry itself?).



Discussion:
FWIW, we considered adding support for reporting CSP violations to Sentry, but not a single person was interested at the time. We can reconsider if you'd want to use it. :)

—
Sent from Mailbox for iPhone

On Mon, Oct 21, 2013 at 8:30 AM, Donald Stufft notifications@github.com
wrote:

> ## In #93 a Content Security Policy was added, however reports are not being sent anywhere. Ideally they would go to something like Sentry (perhaps even sentry itself?).
> 
> Reply to this email directly or view it on GitHub:
> https://github.com/dstufft/warehouse/issues/94

PyPI already uses sentry so getting CSP violations into Sentry would be ideal. Mozilla has written a django-csp app too that has a mini sentry inside of it and they might also be interested in it.

Awesome. I'll look into this and see what we need to do. :)

—
Sent from Mailbox for iPhone

On Mon, Oct 21, 2013 at 8:42 AM, Donald Stufft notifications@github.com
wrote:

> ## PyPI already uses sentry so getting CSP violations into Sentry would be ideal. Mozilla has written a django-csp app too that has a mini sentry inside of it and they might also be interested in it.
> 
> Reply to this email directly or view it on GitHub:
> https://github.com/dstufft/warehouse/issues/94#issuecomment-26728550

+1

Oh hey, we can beta test this now in Sentry for those that are interested. @dstufft, gimme a holla.

![](http://cdn.meme.am/instances/50194253.jpg)


Resolving patch:
diff --git a/warehouse/config.py b/warehouse/config.py
--- a/warehouse/config.py
+++ b/warehouse/config.py
@@ -53,7 +53,11 @@ def make_wsgi_app(self, *args, **kwargs):
 
 def content_security_policy_tween_factory(handler, registry):
     policy = registry.settings.get("csp", {})
-    policy = "; ".join([" ".join([k] + v) for k, v in sorted(policy.items())])
+    policy = "; ".join([
+        " ".join([k] + [v2 for v2 in v if v2 is not None])
+        for k, v in sorted(policy.items())
+        if [v2 for v2 in v if v2 is not None]
+    ])
 
     def content_security_policy_tween(request):
         resp = handler(request)
@@ -159,6 +163,7 @@ def configure(settings=None):
     maybe_set(settings, "aws.region", "AWS_REGION")
     maybe_set(settings, "celery.broker_url", "AMQP_URL")
     maybe_set(settings, "celery.result_url", "REDIS_URL")
+    maybe_set(settings, "csp.report_uri", "CSP_REPORT_URI")
     maybe_set(settings, "database.url", "DATABASE_URL")
     maybe_set(settings, "elasticsearch.url", "ELASTICSEARCH_URL")
     maybe_set(settings, "sentry.dsn", "SENTRY_DSN")
@@ -324,6 +329,7 @@ def configure(settings=None):
             ],
             "referrer": ["cross-origin"],
             "reflected-xss": ["block"],
+            "report-uri": [config.registry.settings.get("csp.report_uri")],
             "script-src": ["'self'"],
             "style-src": ["'self'"],
         },


Test patch:
diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py
--- a/tests/unit/test_config.py
+++ b/tests/unit/test_config.py
@@ -397,6 +397,7 @@ def __init__(self):
                 ],
                 "referrer": ["cross-origin"],
                 "reflected-xss": ["block"],
+                "report-uri": [None],
                 "script-src": ["'self'"],
                 "style-src": ["'self'"],
             },