railroader 4.3.4

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 (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,179 @@
1
+ require 'railroader/options'
2
+
3
+ module Railroader
4
+
5
+ # Implements handling of running Railroader from the command line.
6
+ class Commandline
7
+ class << self
8
+
9
+ # Main method to run Railroader from the command line.
10
+ #
11
+ # If no options are provided, ARGV will be parsed and used instead.
12
+ # Otherwise, the options are expected to be a Hash like the one returned
13
+ # after ARGV is parsed.
14
+ def start options = nil, app_path = "."
15
+
16
+ unless options
17
+ options, app_path = parse_options ARGV
18
+ end
19
+
20
+ run options, app_path
21
+ end
22
+
23
+ # Runs everything:
24
+ #
25
+ # - `set_interrupt_handler`
26
+ # - `early_exit_options`
27
+ # - `set_options`
28
+ # - `check_latest`
29
+ # - `run_report`
30
+ def run options, default_app_path = "."
31
+ set_interrupt_handler options
32
+ early_exit_options options
33
+ set_options options, default_app_path
34
+ check_latest if options[:ensure_latest]
35
+ run_report options
36
+ end
37
+
38
+ # Check for the latest version.
39
+ #
40
+ # If the latest version is newer, quit with a message.
41
+ def check_latest
42
+ if error = Railroader.ensure_latest
43
+ quit Railroader::Not_Latest_Version_Exit_Code, error
44
+ end
45
+ end
46
+
47
+ # Runs a comparison report based on the options provided.
48
+ def compare_results options
49
+ require 'json'
50
+ vulns = Railroader.compare options.merge(:quiet => options[:quiet])
51
+
52
+ if options[:comparison_output_file]
53
+ File.open options[:comparison_output_file], "w" do |f|
54
+ f.puts JSON.pretty_generate(vulns)
55
+ end
56
+
57
+ Railroader.notify "Comparison saved in '#{options[:comparison_output_file]}'"
58
+ else
59
+ puts JSON.pretty_generate(vulns)
60
+ end
61
+
62
+ if options[:exit_on_warn] && vulns[:new].count > 0
63
+ quit Railroader::Warnings_Found_Exit_Code
64
+ end
65
+ end
66
+
67
+ # Handle options that exit without generating a report.
68
+ def early_exit_options options
69
+ if options[:list_checks] or options[:list_optional_checks]
70
+ Railroader.list_checks options
71
+ quit
72
+ elsif options[:create_config]
73
+ Railroader.dump_config options
74
+ quit
75
+ elsif options[:show_help]
76
+ puts Railroader::Options.create_option_parser({})
77
+ quit
78
+ elsif options[:show_version]
79
+ require 'railroader/version'
80
+ puts "railroader #{Railroader::Version}"
81
+ quit
82
+ end
83
+ end
84
+
85
+ # Parse ARGV-style array of options.
86
+ #
87
+ # Exits if options are invalid.
88
+ #
89
+ # Returns an option hash and the app_path.
90
+ def parse_options argv
91
+ begin
92
+ options, _ = Railroader::Options.parse! argv
93
+ rescue OptionParser::ParseError => e
94
+ $stderr.puts e.message
95
+ $stderr.puts "Please see `railroader --help` for valid options"
96
+ quit(-1)
97
+ end
98
+
99
+ if argv[-1]
100
+ app_path = argv[-1]
101
+ else
102
+ app_path = "."
103
+ end
104
+
105
+ return options, app_path
106
+ end
107
+
108
+ # Exits with the given exit code and prints out the message, if given.
109
+ #
110
+ # Override this method for different behavior.
111
+ def quit exit_code = 0, message = nil
112
+ warn message if message
113
+ exit exit_code
114
+ end
115
+
116
+ # Runs a regular report based on the options provided.
117
+ def regular_report options
118
+ tracker = run_railroader options
119
+
120
+ if tracker.options[:exit_on_warn] and not tracker.filtered_warnings.empty?
121
+ quit Railroader::Warnings_Found_Exit_Code
122
+ end
123
+
124
+ if tracker.options[:exit_on_error] and tracker.errors.any?
125
+ quit Railroader::Errors_Found_Exit_Code
126
+ end
127
+ end
128
+
129
+ # Actually run Railroader.
130
+ #
131
+ # Returns a Tracker object.
132
+ def run_railroader options
133
+ Railroader.run options.merge(:print_report => true, :quiet => options[:quiet])
134
+ end
135
+
136
+ # Run either a comparison or regular report based on options provided.
137
+ def run_report options
138
+ begin
139
+ if options[:previous_results_json]
140
+ compare_results options
141
+ else
142
+ regular_report options
143
+ end
144
+ rescue Railroader::NoApplication => e
145
+ quit Railroader::No_App_Found_Exit_Code, e.message
146
+ rescue Railroader::MissingChecksError => e
147
+ quit Railroader::Missing_Checks_Exit_Code, e.message
148
+ end
149
+ end
150
+
151
+ # Sets interrupt handler to gracefully handle Ctrl+C
152
+ def set_interrupt_handler options
153
+ trap("INT") do
154
+ warn "\nInterrupted - exiting."
155
+
156
+ if options[:debug]
157
+ warn caller
158
+ end
159
+
160
+ exit!
161
+ end
162
+ end
163
+
164
+ # Modifies options, including setting the app_path
165
+ # if none is given in the options hash.
166
+ def set_options options, default_app_path = "."
167
+ unless options[:app_path]
168
+ options[:app_path] = default_app_path
169
+ end
170
+
171
+ if options[:quiet].nil?
172
+ options[:quiet] = :command_line
173
+ end
174
+
175
+ options
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,66 @@
1
+ # extracting the diff logic to it's own class for consistency. Currently handles
2
+ # an array of Railroader::Warnings or plain hash representations.
3
+ class Railroader::Differ
4
+ DEFAULT_HASH = {:new => [], :fixed => []}
5
+ OLD_WARNING_KEYS = [:warning_type, :location, :code, :message, :file, :link, :confidence, :user_input]
6
+ attr_reader :old_warnings, :new_warnings
7
+
8
+ def initialize new_warnings, old_warnings
9
+ @new_warnings = new_warnings
10
+ @old_warnings = old_warnings
11
+ end
12
+
13
+ def diff
14
+ # get the type of elements
15
+ return DEFAULT_HASH if @new_warnings.empty?
16
+
17
+ warnings = {}
18
+ warnings[:new] = @new_warnings - @old_warnings
19
+ warnings[:fixed] = @old_warnings - @new_warnings
20
+
21
+ second_pass(warnings)
22
+ end
23
+
24
+ # second pass to cleanup any vulns which have changed in line number only.
25
+ # Given a list of new warnings, delete pairs of new/fixed vulns that differ
26
+ # only by line number.
27
+ # Horrible O(n^2) performance. Keep n small :-/
28
+ def second_pass(warnings)
29
+ # keep track of the number of elements deleted because the index numbers
30
+ # won't update as the list is modified
31
+ elements_deleted_offset = 0
32
+
33
+ # dup this list since we will be deleting from it and the iterator gets confused.
34
+ # use _with_index for fast deletion as opposed to .reject!{|obj| obj == *_warning}
35
+ warnings[:new].dup.each_with_index do |new_warning, new_warning_id|
36
+ warnings[:fixed].each_with_index do |fixed_warning, fixed_warning_id|
37
+ if eql_except_line_number new_warning, fixed_warning
38
+ warnings[:new].delete_at(new_warning_id - elements_deleted_offset)
39
+ elements_deleted_offset += 1
40
+ warnings[:fixed].delete_at(fixed_warning_id)
41
+ break
42
+ end
43
+ end
44
+ end
45
+
46
+ warnings
47
+ end
48
+
49
+ def eql_except_line_number new_warning, fixed_warning
50
+ # can't do this ahead of time, as callers may be expecting a Railroader::Warning
51
+ if new_warning.is_a? Railroader::Warning
52
+ new_warning = new_warning.to_hash
53
+ fixed_warning = fixed_warning.to_hash
54
+ end
55
+
56
+ if new_warning[:fingerprint] and fixed_warning[:fingerprint]
57
+ new_warning[:fingerprint] == fixed_warning[:fingerprint]
58
+ else
59
+ OLD_WARNING_KEYS.each do |attr|
60
+ return false if new_warning[attr] != fixed_warning[attr]
61
+ end
62
+
63
+ true
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,54 @@
1
+ module Railroader
2
+ ASTFile = Struct.new(:path, :ast)
3
+
4
+ # This class handles reading and parsing files.
5
+ class FileParser
6
+ attr_reader :file_list
7
+
8
+ def initialize tracker, app_tree
9
+ @tracker = tracker
10
+ @timeout = @tracker.options[:parser_timeout]
11
+ @app_tree = app_tree
12
+ @file_list = {}
13
+ end
14
+
15
+ def parse_files list, type
16
+ read_files list, type do |path, contents|
17
+ if ast = parse_ruby(contents, path)
18
+ ASTFile.new(path, ast)
19
+ end
20
+ end
21
+ end
22
+
23
+ def read_files list, type
24
+ @file_list[type] ||= []
25
+
26
+ list.each do |path|
27
+ result = yield path, read_path(path)
28
+ if result
29
+ @file_list[type] << result
30
+ end
31
+ end
32
+ end
33
+
34
+ def parse_ruby input, path
35
+ begin
36
+ Railroader.debug "Parsing #{path}"
37
+ RubyParser.new.parse input, path, @timeout
38
+ rescue Racc::ParseError => e
39
+ @tracker.error e, "Could not parse #{path}"
40
+ nil
41
+ rescue Timeout::Error => e
42
+ @tracker.error Exception.new("Parsing #{path} took too long (> #{@timeout} seconds). Try increasing the limit with --parser-timeout"), caller
43
+ nil
44
+ rescue => e
45
+ @tracker.error e.exception(e.message + "\nWhile processing #{path}"), e.backtrace
46
+ nil
47
+ end
48
+ end
49
+
50
+ def read_path path
51
+ @app_tree.read_path path
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,133 @@
1
+ /* CSS style used for HTML reports */
2
+
3
+ body {
4
+ font-family: sans-serif;
5
+ color: #161616;
6
+ }
7
+
8
+ a {
9
+ color: #161616;
10
+ }
11
+
12
+ p {
13
+ font-weight: bold;
14
+ font-size: 11pt;
15
+ color: #2D0200;
16
+ }
17
+
18
+ th {
19
+ background-color: #980905;
20
+ border-bottom: 5px solid #530200;
21
+ color: white;
22
+ font-size: 11pt;
23
+ padding: 1px 8px 1px 8px;
24
+ }
25
+
26
+ td {
27
+ border-bottom: 2px solid white;
28
+ font-family: monospace;
29
+ padding: 5px 8px 1px 8px;
30
+ }
31
+
32
+ table {
33
+ background-color: #FCF4D4;
34
+ border-collapse: collapse;
35
+ }
36
+
37
+ h1 {
38
+ color: #2D0200;
39
+ font-size: 14pt;
40
+ }
41
+
42
+ h2 {
43
+ color: #2D0200;
44
+ font-size: 12pt;
45
+ }
46
+
47
+ span.high-confidence {
48
+ font-weight:bold;
49
+ color: red;
50
+ }
51
+
52
+ span.med-confidence {
53
+ }
54
+
55
+ span.weak-confidence {
56
+ color:gray;
57
+ }
58
+
59
+ div.warning_message {
60
+ cursor: pointer;
61
+ }
62
+
63
+ div.warning_message:hover {
64
+ background-color: white;
65
+ }
66
+
67
+ table caption {
68
+ background-color: #FFE;
69
+ padding: 2px;
70
+ }
71
+
72
+ table.context {
73
+ margin-top: 5px;
74
+ margin-bottom: 5px;
75
+ border-left: 1px solid #90e960;
76
+ color: #212121;
77
+ }
78
+
79
+ tr.context {
80
+ background-color: white;
81
+ }
82
+
83
+ tr.first {
84
+ border-top: 1px solid #7ecc54;
85
+ padding-top: 2px;
86
+ }
87
+
88
+ tr.error {
89
+ background-color: #f4c1c1 !important
90
+ }
91
+
92
+ tr.near_error {
93
+ background-color: #f4d4d4 !important
94
+ }
95
+
96
+ tr.alt {
97
+ background-color: #e8f4d4;
98
+ }
99
+
100
+ td.context {
101
+ padding: 2px 10px 0px 6px;
102
+ border-bottom: none;
103
+ }
104
+
105
+ td.context_line {
106
+ padding: 2px 8px 0px 7px;
107
+ border-right: 1px solid #b3bda4;
108
+ border-bottom: none;
109
+ color: #6e7465;
110
+ }
111
+
112
+ pre.context {
113
+ margin-bottom: 1px;
114
+ }
115
+
116
+ .user_input {
117
+ background-color: #fcecab;
118
+ }
119
+
120
+ div.render_path {
121
+ display: none;
122
+ background-color: #ffe;
123
+ padding: 5px;
124
+ margin: 2px 0px 2px 0px;
125
+ }
126
+
127
+ div.template_name {
128
+ cursor: pointer;
129
+ }
130
+
131
+ div.template_name:hover {
132
+ background-color: white;
133
+ }