csp_report 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +5 -0
  3. data/README.md +64 -24
  4. data/app/assets/javascripts/csp_report.js +2 -0
  5. data/app/assets/javascripts/csp_report/application.js +1 -0
  6. data/app/assets/javascripts/csp_report/report.js.coffee +4 -0
  7. data/app/assets/stylesheets/csp_report/bootstrap_and_overrides.css +7 -0
  8. data/app/assets/stylesheets/csp_report/csp_report.css.sass +19 -15
  9. data/app/controllers/csp_report/csp_reports_controller.rb +135 -0
  10. data/app/helpers/csp_report/headers_helpers.rb +32 -0
  11. data/app/views/csp_report/csp_reports/index.html.haml +60 -35
  12. data/app/views/csp_report/csp_reports/report_by_ip.html.haml +45 -0
  13. data/app/views/csp_report/csp_reports/report_by_rule.html.haml +46 -0
  14. data/app/views/csp_report/csp_reports/report_by_source.html.haml +46 -0
  15. data/config/routes.rb +4 -1
  16. data/lib/csp_report.rb +2 -0
  17. data/lib/csp_report/version.rb +1 -1
  18. data/lib/generators/csp_report/highcharts_include_generator.rb +14 -0
  19. data/lib/generators/csp_report/install_generator.rb +2 -0
  20. data/spec/controllers/csp_report/csp_reports_controller_spec.rb +132 -47
  21. data/spec/dummy/log/test.log +32398 -0
  22. data/spec/dummy/tmp/cache/assets/test/sass/745019acb880ec9412f97713489f02ba42209a06/csp_report.css.sassc +0 -0
  23. data/spec/dummy/tmp/cache/assets/test/sprockets/04b3e69eb694573268093bc96a12cb36 +0 -0
  24. data/spec/dummy/tmp/cache/assets/test/sprockets/05c90a274261cfca1eb2c000659570f5 +0 -0
  25. data/spec/dummy/tmp/cache/assets/test/sprockets/22f7ca496c173fb6290675535b2ea867 +0 -0
  26. data/spec/dummy/tmp/cache/assets/test/sprockets/27b25bddc744ae04b7e3f44fc2ff7b0a +0 -0
  27. data/spec/dummy/tmp/cache/assets/test/sprockets/2a6dae572905cab4d1414332fe21dd75 +0 -0
  28. data/spec/dummy/tmp/cache/assets/test/sprockets/325cfe516884cee28f48dc297246b1fc +0 -0
  29. data/spec/dummy/tmp/cache/assets/test/sprockets/391546e93f4c1edddf588160a1cedc5a +0 -0
  30. data/spec/dummy/tmp/cache/assets/test/sprockets/4949b199f7a3f61704ee406dfc99e38c +0 -0
  31. data/spec/dummy/tmp/cache/assets/test/sprockets/4f12538a5db5fd7fe75ebdcb6dc9b251 +0 -0
  32. data/spec/dummy/tmp/cache/assets/test/sprockets/50d961649ccb35a76acd4f63f6250361 +0 -0
  33. data/spec/dummy/tmp/cache/assets/test/sprockets/51522c13c1c4f9cf7dcfad7b204cf749 +0 -0
  34. data/spec/dummy/tmp/cache/assets/test/sprockets/56f7ae58d3064c45987cc434559f4dcb +0 -0
  35. data/spec/dummy/tmp/cache/assets/test/sprockets/5d4b85a2814f8d22d23ad047618fe032 +0 -0
  36. data/spec/dummy/tmp/cache/assets/test/sprockets/5d91dbec07ef096002d3f884edec8b55 +0 -0
  37. data/spec/dummy/tmp/cache/assets/test/sprockets/641ce249906eb1e5e40fe7309193e5a6 +0 -0
  38. data/spec/dummy/tmp/cache/assets/test/sprockets/71f1e2bbe4e3226070159a95e1690af9 +0 -0
  39. data/spec/dummy/tmp/cache/assets/test/sprockets/7f9fe739367238fbe3fe92a0362d8f33 +0 -0
  40. data/spec/dummy/tmp/cache/assets/test/sprockets/9b94cd42c6d3c0778772d609a4d7006d +0 -0
  41. data/spec/dummy/tmp/cache/assets/test/sprockets/b2fb1d4fcfbdd0431ec50d36c324e769 +0 -0
  42. data/spec/dummy/tmp/cache/assets/test/sprockets/bf4db1839fb7adc3305b797e33f5902c +0 -0
  43. data/spec/dummy/tmp/cache/assets/test/sprockets/d1841c51cd5922191135ddd5c6ed2b70 +0 -0
  44. data/spec/dummy/tmp/cache/assets/test/sprockets/dc4c1ce2dc434402713320ef23981262 +0 -0
  45. data/spec/dummy/tmp/cache/assets/test/sprockets/dd40235a4b424b2f80c80fe5cb993736 +0 -0
  46. data/spec/dummy/tmp/cache/assets/test/sprockets/de041484110f42c73b00c21167cfc7c2 +0 -0
  47. data/spec/dummy/tmp/cache/assets/test/sprockets/faef24ee109a081ff0b9346c27872274 +0 -0
  48. data/spec/factories/csp_report_csp_reports.rb +14 -6
  49. data/spec/features/csp_report/csp_reports_index_spec.rb +17 -0
  50. data/spec/features/csp_report/csp_reports_report_by_ip_spec.rb +12 -2
  51. data/spec/features/csp_report/csp_reports_report_by_rule_spec.rb +21 -0
  52. data/spec/features/csp_report/csp_reports_report_by_source_spec.rb +24 -0
  53. data/spec/routing/csp_reports_routes_spec.rb +9 -0
  54. data/spec/spec_helper.rb +1 -3
  55. metadata +114 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed867030fb43d8172decce4b81cebc84457f71ac
4
- data.tar.gz: 984d3c43474832016053f1eb3897ce2b8aff975a
3
+ metadata.gz: 4c3df7be47bd57116be91c9f07e8abdd00e1d34a
4
+ data.tar.gz: 66ff93264d5f432ecd4b878a2fbd9ce0a29024bf
5
5
  SHA512:
6
- metadata.gz: b7420708abd3a6e5766508f96c00cc5b8263396fd3ddfaa7336b529413e755589a11200c07dd8f8d690769a7bf0a9601dc40bea6d66a38928092a6aa8ef3161e
7
- data.tar.gz: 27a94ad89c75a763a98af01e8fc4b3872594270713bb85cc0018a5dd3fe748035b6bcad35fd4e5d09d58475585925ceb73280c410012099345f2b4bd778a39e2
6
+ metadata.gz: 0ed72f415782aa6d14d49b9d3a64a416ae1eea4e4d9f15dd3dcafb0aca4a47d035ed1787e922a253e7e28c0e82acad7be78b4d9dca664ec2ca519f2bc699d361
7
+ data.tar.gz: 9805a4912c9111cebbc1a91e530ef4bd68b2edc05d08fb090eb1d651a5a8e6474f4ff297fd776a5fc75f753c7f1bd7e53f165a6cb02311598d0d864cd53a6228
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ * From 0.4.0
2
+ - Follow the upgrade instruction to add the JS hook
3
+ - Adds charting capabilities for data visualization
4
+ - Adds styling from bootstrap and a common navigation pattern
5
+
1
6
  * From 0.3.0
2
7
  - Developer additions (test coverage, Guard+Spork, ...)
3
8
  - Mount point for the engine is now configurable as a parameter of the
data/README.md CHANGED
@@ -18,11 +18,17 @@ page. However, elements have a class so you can add some CSS style before I
18
18
 
19
19
  I promise something cleaner when I'll get to v1.
20
20
 
21
+ [Installation](#install) | [Upgrade](#upgrade-notes) |
22
+ [Configuration](#trying-it-out) | [Description](#what-is-csp)
23
+
21
24
  **Careful**: If migrating from 0.1.x, please follow
22
25
  [these instructions](#upgrade-from-01x)
23
26
 
24
27
  **Careful**: If migrating from 0.2.x or below, you can follow
25
- [these instructions](#upgrade-from-02x). This is not mandatory.
28
+ [these instructions](#upgrade-from-02x-or-below). This is not mandatory.
29
+
30
+ **Careful**: If migrating from 0.3.x or below, you can follow
31
+ [these instructions](#upgrade-from-03x-or-below). This is mandatory.
26
32
 
27
33
  What is CSP
28
34
  ===========
@@ -48,8 +54,29 @@ Features
48
54
 
49
55
  * Provides a *csp_report* resource that stores the reported violations.
50
56
  * Displays the violation for analysis
57
+ * Keeps up-to-date with the CSP W3C RFC
51
58
  * Future: provide visualization aids on the report data
52
59
 
60
+ Why using this gem
61
+ ==================
62
+
63
+ CSP is yet another layer of protection, basically relying on the browser to do
64
+ some level of control. This is a way to prevent some man in the middle attack
65
+ where someone intercepts the server response and try to change it. While not
66
+ foolproof, it's a good additional security layer.
67
+
68
+ This gem comes in handy for 2 reasons:
69
+ * First, when activating CSP directives on your existing site, it is likely
70
+ that you'll have a hard
71
+ time figuring out all the sources you are using. By recording all the breaches,
72
+ this gem allows you to setup a policy, run a crawler for example, and then
73
+ look at what is reported as breaches. It will help you getting rid of your
74
+ inline js and so on.
75
+ * Second, in normal production mode, it'll help you monitor the situation and
76
+ see if your server has been victim of some injection (if some input is not
77
+ sanitize properly) or if your users are being attacked in some way (in which
78
+ case you might gather stats and maybe warn them in one way or another).
79
+
53
80
  Install
54
81
  =======
55
82
 
@@ -117,6 +144,26 @@ in one of your HTML rendered file and launch it in a browser. If the setup is
117
144
  correct and you browser supports CSP, the script will not play (no pop-up) and
118
145
  you'll have one more record in the /csp/csp_reports list.
119
146
 
147
+ Tuning the engine
148
+ =================
149
+
150
+ #### Overriding the engine's CSS
151
+
152
+ The engine comes packages with some CSS so that the page do not look ugly.
153
+ Since it is meant to be available for site admins or developers, the look&feel
154
+ is a secondary concern. Still you might want to customize it for consistency
155
+ with your site.
156
+ This is easy to do. Indeed, all the classes used are namespaced with *csp-report*.
157
+ To customize the CSS, just create the following file:
158
+ *app/assets/stylesheets/csp_report/csp_report.css*
159
+
160
+ Careful though, this is going to remove all the styles definition, so you'll
161
+ have to redefine every single one of them.
162
+
163
+ #### Changing the CSP rule per controller/action
164
+
165
+ TODO - gbataille - Fill in this section
166
+
120
167
  Utilities
121
168
  =========
122
169
 
@@ -127,26 +174,6 @@ typically used in the response header construction.
127
174
  I could not get it to work as I wanted, in a view you can use *csp_report.routes.url_helpers*
128
175
  and it will give you access to all the engine URL helpers.
129
176
 
130
- Why using this gem
131
- ==================
132
-
133
- CSP is yet another layer of protection, basically relying on the browser to do
134
- some level of control. This is a way to prevent some man in the middle attack
135
- where someone intercepts the server response and try to change it. While not
136
- foolproof, it's a good additional security layer.
137
-
138
- This gem comes in handy for 2 reasons:
139
- * First, when activating CSP directives on your existing site, it is likely
140
- that you'll have a hard
141
- time figuring out all the sources you are using. By recording all the breaches,
142
- this gem allows you to setup a policy, run a crawler for example, and then
143
- look at what is reported as breaches. It will help you getting rid of your
144
- inline js and so on.
145
- * Second, in normal production mode, it'll help you monitor the situation and
146
- see if your server has been victim of some injection (if some input is not
147
- sanitize properly) or if your users are being attacked in some way (in which
148
- case you might gather stats and maybe warn them in one way or another).
149
-
150
177
  To come
151
178
  =======
152
179
 
@@ -154,8 +181,11 @@ To come
154
181
  * Support of CSP 1.1 draft spec
155
182
  * Eased data mining
156
183
 
184
+ Upgrade notes
185
+ =============
186
+
157
187
  Upgrade from 0.1.x
158
- ==================
188
+ ------------------
159
189
 
160
190
  CAREFUL, 0.2.0 comes with DB changes. I won't do that in a minor after we are at
161
191
  v1, but for the moment, I thought it would not trouble too many people.
@@ -167,8 +197,8 @@ rake db:migrate
167
197
  ```
168
198
  before continuing
169
199
 
170
- Upgrade from 0.2.x
171
- ==================
200
+ Upgrade from 0.2.x or below
201
+ ---------------------------
172
202
 
173
203
  Version 0.3.0 comes with a configurable mount point and a couple of helpers that
174
204
  are accessible through the generators.
@@ -185,6 +215,16 @@ rails generate csp_report:mount [NAMESPACE]
185
215
  rails generate csp_report:initializer_install
186
216
  ```
187
217
 
218
+ Upgrade from 0.3.x or below
219
+ ---------------------------
220
+
221
+ Version 0.4.0 and above introduce a new javascript integration point to add the
222
+ highchart library used to produce some visualization of the reporting data.
223
+ The install generator would provide the additional hook. Rather than re-running
224
+ the entire install (not tested), you can either
225
+ * run the `csp_report:highcharts_include` generator
226
+ * or add the `//= require csp_report` in your application.js file.
227
+
188
228
  License
189
229
  =======
190
230
 
@@ -0,0 +1,2 @@
1
+ //= require highcharts/highcharts
2
+ //= require highcharts/highcharts-more
@@ -10,4 +10,5 @@
10
10
  // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
+ //= require twitter/bootstrap
13
14
  //= require_tree .
@@ -0,0 +1,4 @@
1
+ $(document).ready(() ->
2
+ data = $.parseJSON( $("#chart")[0].attributes["data-chart"].value )
3
+ window.chart = new Highcharts.Chart(data)
4
+ )
@@ -0,0 +1,7 @@
1
+ /*
2
+ =require twitter-bootstrap-static/bootstrap
3
+
4
+ Use Font Awesome icons (default)
5
+ To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites"
6
+ =require twitter-bootstrap-static/fontawesome
7
+ */
@@ -1,15 +1,19 @@
1
- .csp-report.report-table
2
- border-style: solid
3
- border-color: #0000AA
4
- border-width: 5px
5
- border-collapse: collapse
6
-
7
- .csp-report.report-cell
8
- padding: 5px
9
- border-style: solid
10
- border-width: 2px
11
-
12
- .csp-report.report-header
13
- padding: 5px
14
- border-style: solid
15
- border-width: 3px
1
+ //= require csp_report/bootstrap_and_overrides
2
+
3
+ .csp-report.row
4
+ // You can override the bootstrap scoffolding here
5
+
6
+ .csp-report.offset3
7
+ // You can override the bootstrap scoffolding here
8
+
9
+ .csp-report.span6
10
+ // You can override the bootstrap scoffolding here
11
+
12
+ // .csp-report.report-table
13
+ //
14
+ // .csp-report.report-cell
15
+ //
16
+ // .csp-report.report-header
17
+ //
18
+ .csp-report.padding-navbar
19
+ padding-top: 45px
@@ -31,4 +31,139 @@ class CspReport::CspReportsController < ApplicationController
31
31
  CspReport::CspReport.delete_all
32
32
  redirect_to csp_reports_path
33
33
  end
34
+
35
+ def report_by_ip
36
+ @report_by_ip = CspReport::CspReport.select(
37
+ "incoming_ip, count(*) as count").group("incoming_ip")
38
+
39
+ data = []
40
+ for report in @report_by_ip
41
+ data.push [report.incoming_ip, report.count]
42
+ end
43
+
44
+ @chart = {
45
+ chart: {
46
+ :defaultSeriesType=>"pie" ,
47
+ :margin=> [50, 200, 60, 170]
48
+ },
49
+ series: [{
50
+ :type=> 'pie',
51
+ :name=> 'Violations by client IP',
52
+ :data=> data
53
+ }],
54
+ title: {text: "By IP"},
55
+ legend: {
56
+ :layout=> 'vertical',
57
+ :style=> {
58
+ :left=> 'auto',
59
+ :bottom=> 'auto',
60
+ :right=> '50px',
61
+ :top=> '100px'
62
+ }
63
+ },
64
+ plotOptions: {
65
+ :pie=>{
66
+ :allowPointSelect=>true,
67
+ :cursor=>"pointer" ,
68
+ :dataLabels=>{
69
+ :enabled=>true,
70
+ :color=>"black",
71
+ :style=>{
72
+ :font=>"13px Trebuchet MS, Verdana, sans-serif"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ end
79
+
80
+ def report_by_rule
81
+ @report_by_rule = CspReport::CspReport.select(
82
+ "violated_directive, count(*) as count").group("violated_directive")
83
+
84
+ data = []
85
+ for report in @report_by_rule
86
+ data.push [report.violated_directive, report.count]
87
+ end
88
+
89
+ @chart = {
90
+ chart: {
91
+ :defaultSeriesType=>"pie" ,
92
+ :margin=> [50, 200, 60, 170]
93
+ },
94
+ series: [{
95
+ :type=> 'pie',
96
+ :name=> 'Violations by violated policy',
97
+ :data=> data
98
+ }],
99
+ title: {text: "By rule"},
100
+ legend: {
101
+ :layout=> 'vertical',
102
+ :style=> {
103
+ :left=> 'auto',
104
+ :bottom=> 'auto',
105
+ :right=> '50px',
106
+ :top=> '100px'
107
+ }
108
+ },
109
+ plotOptions: {
110
+ :pie=>{
111
+ :allowPointSelect=>true,
112
+ :cursor=>"pointer" ,
113
+ :dataLabels=>{
114
+ :enabled=>true,
115
+ :color=>"black",
116
+ :style=>{
117
+ :font=>"13px Trebuchet MS, Verdana, sans-serif"
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ end
124
+
125
+ def report_by_source
126
+ @report_by_source = CspReport::CspReport.select(
127
+ "document_uri, count(*) as count").group("document_uri")
128
+
129
+ data = []
130
+ for report in @report_by_source
131
+ data.push [report.document_uri, report.count]
132
+ end
133
+
134
+ @chart = {
135
+ chart: {
136
+ :defaultSeriesType=>"pie" ,
137
+ :margin=> [50, 200, 60, 170]
138
+ },
139
+ series: [{
140
+ :type=> 'pie',
141
+ :name=> 'Violations by source document URI',
142
+ :data=> data
143
+ }],
144
+ title: {text: "By source"},
145
+ legend: {
146
+ :layout=> 'vertical',
147
+ :style=> {
148
+ :left=> 'auto',
149
+ :bottom=> 'auto',
150
+ :right=> '50px',
151
+ :top=> '100px'
152
+ }
153
+ },
154
+ plotOptions: {
155
+ :pie=>{
156
+ :allowPointSelect=>true,
157
+ :cursor=>"pointer" ,
158
+ :dataLabels=>{
159
+ :enabled=>true,
160
+ :color=>"black",
161
+ :style=>{
162
+ :font=>"13px Trebuchet MS, Verdana, sans-serif"
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ end
34
169
  end
@@ -0,0 +1,32 @@
1
+ module CspReport
2
+ module HeadersHelper
3
+ def add_navigation_header
4
+ <<-CONTENT
5
+ <div class='csp-report row'>
6
+ <div class='csp-report navbar navbar-fixed-top'>
7
+ <div class='csp-report navbar-inner'>
8
+ <div class='csp-report container'>
9
+ <a class='brand' href="#">CSP Reports</a>
10
+ <ul class='nav'>
11
+ <li class='active'>
12
+ <a href=#{csp_reports_path}>Violations</a>
13
+ </li>
14
+ <li class='divider-vertical'/>
15
+ <li>
16
+ <a href=#{csp_reports_report_by_ip_path}>By IP</a>
17
+ </li>
18
+ <li>
19
+ <a href=#{csp_reports_report_by_rule_path}>By Violated Directive</a>
20
+ </li>
21
+ <li>
22
+ <a href=#{csp_reports_report_by_source_path}>By Source Document URI</a>
23
+ </li>
24
+ </ul>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ CONTENT
30
+ end
31
+ end
32
+ end
@@ -1,38 +1,63 @@
1
1
  =stylesheet_link_tag "csp_report/csp_report.css"
2
2
 
3
- %table.csp-report.report-table
4
- %tr.csp-report.report-row
5
- %th.csp-report.report-header
6
- ID
7
- %th.csp-report.report-header
8
- Document URI
9
- %th.csp-report.report-header
10
- Referrer
11
- %th.csp-report.report-header
12
- Server Policy
13
- %th.csp-report.report-header
14
- Violated Directive
15
- %th.csp-report.report-header
16
- Blocked URI
17
- %th.csp-report.report-header
18
- Incoming IP
19
- %th.csp-report.report-header
20
- Reported At
21
- %th.csp-report.report-header
22
- Actions
23
- - @reports.each do |report|
24
- %tr.csp-report.report-row
25
- %td.csp-report.report-cell=report.id
26
- %td.csp-report.report-cell=report.document_uri
27
- %td.csp-report.report-cell=report.referrer
28
- %td.csp-report.report-cell=report.original_policy
29
- %td.csp-report.report-cell=report.violated_directive
30
- %td.csp-report.report-cell=report.blocked_uri
31
- %td.csp-report.report-cell=report.incoming_ip
32
- %td.csp-report.report-cell=report.created_at
33
- %td.csp-report.report-cell
34
- =link_to('Delete violation', csp_report_path(report.id), method: 'delete')
3
+ -# TODO: gbataille - Factorize this in a layout
4
+ .csp-report.row
5
+ .csp-report.navbar.navbar-fixed-top
6
+ .csp-report.navbar-inner
7
+ .csp-report.container
8
+ %a.brand{href: "#"}
9
+ CSP Reports
10
+ %ul.nav
11
+ %li.active
12
+ =link_to "Violations", csp_reports_path
13
+ %li.divider-vertical
14
+ %li
15
+ =link_to "By IP", csp_reports_report_by_ip_path
16
+ %li
17
+ =link_to "By Violated Directive", csp_reports_report_by_rule_path
18
+ %li
19
+ =link_to "By Source Document URI", csp_reports_report_by_source_path
35
20
 
36
- %p
37
- =link_to "Delete All", csp_reports_destroy_all_path,
38
- data: {confirm: "Are you sure you want to delete all the violation reports?"}
21
+ .csp-report.row.padding-navbar
22
+ .csp-report.offset2.span8
23
+ %table.csp-report.report-table.table.table-striped.table-condensed
24
+ %thead
25
+ %tr.csp-report.report-row
26
+ %th.csp-report.report-header
27
+ ID
28
+ %th.csp-report.report-header
29
+ Document URI
30
+ %th.csp-report.report-header
31
+ Referrer
32
+ %th.csp-report.report-header
33
+ Server Policy
34
+ %th.csp-report.report-header
35
+ Violated Directive
36
+ %th.csp-report.report-header
37
+ Blocked URI
38
+ %th.csp-report.report-header
39
+ Incoming IP
40
+ %th.csp-report.report-header
41
+ Reported At
42
+ %th.csp-report.report-header
43
+ Actions
44
+ %tbody
45
+ - @reports.each do |report|
46
+ %tr.csp-report.report-row
47
+ %td.csp-report.report-cell=report.id
48
+ %td.csp-report.report-cell=report.document_uri
49
+ %td.csp-report.report-cell=report.referrer
50
+ %td.csp-report.report-cell=report.original_policy
51
+ %td.csp-report.report-cell=report.violated_directive
52
+ %td.csp-report.report-cell=report.blocked_uri
53
+ %td.csp-report.report-cell=report.incoming_ip
54
+ %td.csp-report.report-cell=report.created_at
55
+ %td.csp-report.report-cell
56
+ =link_to('Delete violation', csp_report_path(report.id), method: 'delete')
57
+
58
+ .csp-report.row
59
+ .csp-report.offset2.span8
60
+
61
+ %p.csp-report.btn.btn-danger
62
+ =link_to "Delete All", csp_reports_destroy_all_path,
63
+ data: {confirm: "Are you sure you want to delete all the violation reports?"}