puppet-validator 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +39 -104
- data/bin/puppet-validator +38 -1
- data/config.ru +0 -2
- data/lib/puppet-validator.rb +181 -136
- data/lib/puppet-validator/helpers.rb +40 -0
- data/lib/puppet-validator/validators.rb +5 -0
- data/lib/puppet-validator/validators/lint.rb +46 -0
- data/lib/puppet-validator/validators/rspec.rb +90 -0
- data/lib/puppet-validator/validators/syntax.rb +96 -0
- data/public/font-awesome-4.7.0/css/font-awesome.css +2337 -0
- data/public/font-awesome-4.7.0/css/font-awesome.min.css +4 -0
- data/public/font-awesome-4.7.0/fonts/FontAwesome.otf +0 -0
- data/public/font-awesome-4.7.0/fonts/fontawesome-webfont.eot +0 -0
- data/public/font-awesome-4.7.0/fonts/fontawesome-webfont.svg +2671 -0
- data/public/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf +0 -0
- data/public/font-awesome-4.7.0/fonts/fontawesome-webfont.woff +0 -0
- data/public/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 +0 -0
- data/public/scripts.js +203 -35
- data/public/styles.css +85 -54
- data/public/validation.js +95 -0
- data/views/index.erb +29 -7
- data/views/result.erb +23 -27
- metadata +33 -43
- data/bin/grapher +0 -44
- data/public/info.png +0 -0
- data/public/prism-default.css +0 -227
- data/public/prism.js +0 -961
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YmUxZGMwYmM3ZGE3MjI0ZjNmZDUxMDdlMDYyYTZjOWExNDg3MzUzMA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 42c7dd8c42d525d1d2b73688beeb01b3595477a1
|
4
|
+
data.tar.gz: d121433916a22680ae5692e59ece41a8f60c9eb4
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MmYyNzkwZGY3MjU5MmExYjExNDA0ZjZkODk2ZjdlMTJmYzYxMzBjNTY4ZDll
|
11
|
-
MWZiNTBlMWMxYTRjZjRjYzc4YWZlY2U4NGNiZTk5MmM0YWEzY2U=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
M2E0NGIwZDQ3NzZmNzliOTE2N2QyMWFjNDYyZWFmY2VlNzU3NjBhYzRiMDIx
|
14
|
-
N2E4ZmRmYzJiYWY0OTc4ZjA2OGVlNzBkYWEzYjY2MWY1NGZlM2RmNGY0NDFh
|
15
|
-
YmVkMWEwYjNmYzdiYmY3ZjBkYTBmNTNkMTk1MmI1NjU4NGQ0YmY=
|
6
|
+
metadata.gz: d8a6b17cef56ab2112e0414d97cfc31e501dc64c6fa9a5f358417cedc0be2ea47b8bcc9ba951367b6aa67c083af72d9ab659c557b2b0ec2645ae5545f02d62cc
|
7
|
+
data.tar.gz: 077da604c15b3beb0cde4513b63f9e01cd4eef89c5b42f91e0135f1f2e582d13f30cbf1a8f1fbdd0fbf2078dfde51eaa97e78b099a26cef3f8471ed0a6cec471
|
data/README.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# Puppet Validator:
|
2
2
|
## Puppet Code Validation as a service
|
3
3
|
|
4
|
-
Puppet Validator is a simple web service that accepts arbitrary code submissions
|
5
|
-
validates it the way `puppet parser validate` would.
|
6
|
-
|
4
|
+
Puppet Validator is a simple web service that accepts arbitrary code submissions
|
5
|
+
and validates it the way `puppet parser validate` and `puppet-lint` would. For
|
6
|
+
simple and self-contained manifests, it can also show you a relationship graph.
|
7
7
|
|
8
8
|
Puppet Validator is completely themeable, albeit rather primitively.
|
9
9
|
|
10
|
+
See an example running on https://validate.puppet.com
|
11
|
+
|
10
12
|
### Usage:
|
11
13
|
|
12
14
|
#### Running the service directly
|
@@ -22,25 +24,33 @@ and will serve content directly out of its installation directory. You can
|
|
22
24
|
override and customize the web content by passing the `-t` or `--theme`
|
23
25
|
command-line argument. See [Creating your own theme](#creating-your-own-theme) below.
|
24
26
|
|
27
|
+
This can load code from several popular paste services and can gist validated
|
28
|
+
code to https://gist.github.com. These gists include a `referer` link back so
|
29
|
+
the gisted code can be re-validated at any time. If you'd like the `referer`
|
30
|
+
check to work properly, make sure to run this with a valid SSL certificate.
|
31
|
+
|
25
32
|
Options:
|
26
33
|
|
27
34
|
-d, --debug Display or log debugging messages
|
28
|
-
|
29
|
-
|
35
|
+
--disable DISABLED_CHECKS Lint checks to disable. Either comma-separated list or filename.
|
36
|
+
-l, --logfile [LOGFILE] Path to logfile. Defaults to no logging, or /var/log/puppet-validator if no filename is passed.
|
30
37
|
-p, --port PORT Port to listen on. Defaults to 9000.
|
31
38
|
-t, --theme THEMEDIR Path to the theme directory.
|
32
|
-
-x, --csrf Protect from cross site request forgery. Requires code to be
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
39
|
+
-x, --csrf Protect from cross site request forgery. Requires code to be submitted for validation via the webpage.
|
40
|
+
-g, --graph Generate relationship graphs from validated code. Requires `graphviz` to be installed.
|
41
|
+
--ssl Run with SSL support. Autogenerates a self-signed certificates by default.
|
42
|
+
--ssl-cert FILE Specify the SSL certificate you'd like use use. Pair with --ssl-key.
|
43
|
+
--ssl-key FILE Specify the SSL key file you'd like use use. Pair with --ssl-cert.
|
44
|
+
|
37
45
|
-h, --help Displays this help
|
38
46
|
|
47
|
+
|
39
48
|
#### Integrating with Middleware
|
40
49
|
|
41
50
|
If you plan to run this as a public service, then you may want to run it under
|
42
|
-
middleware
|
43
|
-
specific implementation will depend on your choice of webserver
|
51
|
+
middleware (such as Phusion Passenger, Puma, or Unicorn) for performance and
|
52
|
+
scalability. The specific implementation will depend on your choice of webserver
|
53
|
+
and middleware.
|
44
54
|
|
45
55
|
To configure Puppet Validator on Apache and Passenger, you'll need to
|
46
56
|
<a href="https://www.phusionpassenger.com/library/install/apache/install/oss/el7/">
|
@@ -81,7 +91,6 @@ require 'puppet-validator'
|
|
81
91
|
logger = Logger.new('/var/log/puppet-validator')
|
82
92
|
logger.level = Logger::WARN
|
83
93
|
|
84
|
-
PuppetValidator.set :puppet_versions, Dir.glob('*').select {|f| File.symlink? f and File.readlink(f) == '.' }
|
85
94
|
PuppetValidator.set :root, File.dirname(__FILE__)
|
86
95
|
PuppetValidator.set :logger, logger
|
87
96
|
|
@@ -93,7 +102,6 @@ PuppetValidator.set :disabled_lint_checks, ['80chars']
|
|
93
102
|
# Protect from cross site request forgery. With this set, code may be
|
94
103
|
# submitted for validation by the website only.
|
95
104
|
#
|
96
|
-
# Note: This will currently break multiple version validation.
|
97
105
|
PuppetValidator.set :csrf, false
|
98
106
|
|
99
107
|
# Provide the option to generate relationship graphs from validated code.
|
@@ -114,17 +122,19 @@ command *will overwrite* existing files, but it will warn you before it does so.
|
|
114
122
|
root@master:~ # cd /etc/puppet-validator/
|
115
123
|
root@master:/etc/puppet-validator # puppet-validator init
|
116
124
|
Initializing directory as new Puppet Validator theme...
|
117
|
-
root@master:/etc/puppet-validator # tree
|
125
|
+
root@master:/etc/puppet-validator # tree -L 2
|
118
126
|
.
|
119
127
|
├── LICENSE
|
120
128
|
├── README.md
|
121
129
|
├── config.ru
|
122
130
|
├── public
|
123
|
-
│ ├──
|
124
|
-
│ ├──
|
125
|
-
│ ├──
|
131
|
+
│ ├── font-awesome-4.7.0
|
132
|
+
│ ├── gist.png
|
133
|
+
│ ├── relationships.html
|
134
|
+
│ ├── scripts.js
|
126
135
|
│ ├── styles.css
|
127
|
-
│
|
136
|
+
│ ├── testing.html
|
137
|
+
│ └── validation.js
|
128
138
|
└── views
|
129
139
|
├── index.erb
|
130
140
|
└── result.erb
|
@@ -132,7 +142,7 @@ command *will overwrite* existing files, but it will warn you before it does so.
|
|
132
142
|
Once you've created your theme, you can start the Puppet Validator service using the `-t`
|
133
143
|
or `--theme` command line arguments to tell Puppet Validator where to find your content.
|
134
144
|
|
135
|
-
root@master:~ # puppet-validator
|
145
|
+
root@master:~ # puppet-validator --theme /etc/puppet-validator/
|
136
146
|
|
137
147
|
Alternatively, you can edit your webserver virtual host configuration to point
|
138
148
|
to the *public* directory within your new theme, as in the example shown above.
|
@@ -171,93 +181,18 @@ PuppetValidator.set :disabled_lint_checks, '/etc/puppet-validator/disabled_check
|
|
171
181
|
|
172
182
|
#### Validating code against multiple Puppet versions
|
173
183
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
versions in different `Location` blocks since version 4.0 by loading separate
|
178
|
-
threads for each.
|
179
|
-
|
180
|
-
We can take advantage of that by configuring multiple Ruby environments using `rvm`
|
181
|
-
or `rbenv` and installing different gemsets. A simple Puppet module to do this
|
182
|
-
is included in the repository, with the caveat that it was designed to fully own
|
183
|
-
a single-purpose VM and has so far only been tested on CentOS 7.
|
184
|
-
|
185
|
-
If configuring manually, you'll need to create a gemset for each Puppet version
|
186
|
-
you want to validate, with something like the following.
|
187
|
-
|
188
|
-
root@master:~ # rvm install ruby-1.9.3-p551
|
189
|
-
Searching for binary rubies, this might take some time.
|
190
|
-
[...]
|
191
|
-
root@master:~ # rvm use 1.9
|
192
|
-
Using /usr/local/rvm/gems/ruby-1.9.3-p551
|
193
|
-
root@master:~ # rvm gemset create puppet2.7.4
|
194
|
-
ruby-1.9.3-p551 - #gemset created /usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4
|
195
|
-
ruby-1.9.3-p551 - #generating puppet2.7.4 wrappers........
|
196
|
-
root@master:~ # rvm gemset use puppet2.7.4
|
197
|
-
Using ruby-1.9.3-p551 with gemset puppet2.7.4
|
198
|
-
root@master:~ # gem install puppet -v 2.7.4
|
199
|
-
[...]
|
200
|
-
root@master:~ # gem install puppet-validator
|
201
|
-
[...]
|
202
|
-
root@master:~ # passenger-config --ruby-command
|
203
|
-
passenger-config was invoked through the following Ruby interpreter:
|
204
|
-
Command: /usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4/wrappers/ruby
|
205
|
-
Version: ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]
|
206
|
-
To use in Apache: PassengerRuby /usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4/wrappers/ruby
|
207
|
-
To use in Nginx : passenger_ruby /usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4/wrappers/ruby
|
208
|
-
To use with Standalone: /usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4/wrappers/ruby /usr/bin/passenger start
|
209
|
-
|
210
|
-
|
211
|
-
## Notes for RVM users
|
212
|
-
Do you want to know which command to use for a different Ruby interpreter? 'rvm use' that Ruby interpreter, then re-run 'passenger-config about ruby-command'.
|
213
|
-
|
214
|
-
Make a note of the `PassengerRuby` command for each gemset. You'll use it in the next step.
|
215
|
-
|
216
|
-
You will need a `Location` block in your Apache `VirtualHost` for each versioned
|
217
|
-
Puppet gemset you created above. The example file below shows blocks for three
|
218
|
-
Puppet versions with the current version installed into the default directory.
|
219
|
-
|
220
|
-
``` Apache
|
221
|
-
<VirtualHost *:80>
|
222
|
-
ServerName vhost.example.com
|
223
|
-
DocumentRoot "/var/www/puppet-validator/public"
|
224
|
-
|
225
|
-
# The default root will validate against the current Puppet version
|
226
|
-
<Directory "/var/www/puppet-validator/public">
|
227
|
-
Options -MultiViews
|
228
|
-
AllowOverride All
|
229
|
-
Require all granted
|
230
|
-
</Directory>
|
231
|
-
|
232
|
-
Alias /2.7.4 /var/www/puppet-validator/2.7.4/public
|
233
|
-
<Location /2.7.4>
|
234
|
-
PassengerBaseURI /2.7.4
|
235
|
-
PassengerAppRoot /var/www/puppet-validator/2.7.4
|
236
|
-
PassengerRuby "/usr/local/rvm/gems/ruby-1.9.3-p551@puppet2.7.4/wrappers/ruby"
|
237
|
-
</Location>
|
238
|
-
|
239
|
-
Alias /3.6.2 /var/www/puppet-validator/3.6.2/public
|
240
|
-
<Location /3.6.2>
|
241
|
-
PassengerBaseURI /3.6.2
|
242
|
-
PassengerAppRoot /var/www/puppet-validator/3.6.2
|
243
|
-
PassengerRuby "/usr/local/rvm/gems/ruby-1.9.3-p551@puppet3.6.2/wrappers/ruby"
|
244
|
-
</Location>
|
245
|
-
|
246
|
-
## Logging
|
247
|
-
ErrorLog "/var/log/httpd/vhost.example.com_error.log"
|
248
|
-
ServerSignature Off
|
249
|
-
CustomLog "/var/log/httpd/vhost.example.com_access.log" combined
|
250
|
-
</VirtualHost>
|
251
|
-
```
|
184
|
+
Puppet Validator runs a new process to validate each submission. This means that
|
185
|
+
it can lazy-load the requested Puppet version on demand. Simply `gem install` all
|
186
|
+
the versions you want and they'll be visible in the drop-down selector.
|
252
187
|
|
253
|
-
|
254
|
-
|
188
|
+
# Installing a specific version
|
189
|
+
root@master:~ # gem install puppet -v 5.3.3
|
255
190
|
|
256
|
-
|
257
|
-
root@master:~ #
|
258
|
-
root@master:~ # ln -s . 3.6.2
|
191
|
+
# Installing several versions at once
|
192
|
+
root@master:~ # gem install puppet:3.8.8 puppet:4.10.0 puppet:5.3.3
|
259
193
|
|
260
|
-
|
194
|
+
If you use the `puppet_validator` module, simply specify the versions you want
|
195
|
+
as an array,
|
261
196
|
|
262
197
|
#### Running standalone with `systemd`
|
263
198
|
|
data/bin/puppet-validator
CHANGED
@@ -12,9 +12,11 @@ options = {
|
|
12
12
|
:root => gemroot,
|
13
13
|
:csrf => false,
|
14
14
|
:graph => false,
|
15
|
+
:spec => '/var/puppet-validator/spec'
|
15
16
|
}
|
16
17
|
logfile = $stderr
|
17
18
|
loglevel = Logger::WARN
|
19
|
+
ssl_opts = {:verify_peer => false}
|
18
20
|
|
19
21
|
optparse = OptionParser.new { |opts|
|
20
22
|
opts.banner = "Usage : puppet-validator [-p <port>] [-l [logfile]] [-t <themedir>] [-d]
|
@@ -47,6 +49,10 @@ optparse = OptionParser.new { |opts|
|
|
47
49
|
options[:root] = arg
|
48
50
|
end
|
49
51
|
|
52
|
+
opts.on("-s SPECDIR", "--spec SPECDIR", "Path to the directory where spec tests are located.") do |arg|
|
53
|
+
options[:spec] = arg
|
54
|
+
end
|
55
|
+
|
50
56
|
opts.on("-x", "--csrf", "Protect from cross site request forgery. Requires code to be submitted for validation via the webpage.") do
|
51
57
|
options[:csrf] = true
|
52
58
|
end
|
@@ -55,6 +61,18 @@ optparse = OptionParser.new { |opts|
|
|
55
61
|
options[:graph] = true
|
56
62
|
end
|
57
63
|
|
64
|
+
opts.on("--ssl", "Run with SSL support. Autogenerates a self-signed certificates by default.") do
|
65
|
+
options[:ssl] = true
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on("--ssl-cert FILE", "Specify the SSL certificate you'd like use use. Pair with --ssl-key.") do |arg|
|
69
|
+
ssl_opts[:cert_chain_file] = arg
|
70
|
+
end
|
71
|
+
|
72
|
+
opts.on("--ssl-key FILE", "Specify the SSL key file you'd like use use. Pair with --ssl-cert.") do |arg|
|
73
|
+
ssl_opts[:private_key_file] = arg
|
74
|
+
end
|
75
|
+
|
58
76
|
opts.separator('')
|
59
77
|
|
60
78
|
opts.on("-h", "--help", "Displays this help") do
|
@@ -84,5 +102,24 @@ else
|
|
84
102
|
logger.level = loglevel
|
85
103
|
options[:logger] = logger
|
86
104
|
|
87
|
-
|
105
|
+
if ssl_opts[:cert_chain_file] and ssl_opts[:private_key_file]
|
106
|
+
options[:ssl] = true
|
107
|
+
end
|
108
|
+
|
109
|
+
# These options should either both be nil or both be Strings
|
110
|
+
unless ssl_opts[:cert_chain_file].class == ssl_opts[:private_key_file].class
|
111
|
+
raise 'You must specify both the certificate and key file!'
|
112
|
+
end
|
113
|
+
|
114
|
+
PuppetValidator.run!(options) do |server|
|
115
|
+
if options[:ssl]
|
116
|
+
if server.respond_to? 'ssl='
|
117
|
+
logger.info 'Enabling SSL support.'
|
118
|
+
server.ssl = true
|
119
|
+
server.ssl_options = ssl_opts
|
120
|
+
else
|
121
|
+
logger.warn "Please 'gem install thin' or run via an app server for SSL support."
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
88
125
|
end
|
data/config.ru
CHANGED
@@ -4,7 +4,6 @@ require 'puppet-validator'
|
|
4
4
|
logger = Logger.new('/var/log/puppet-validator')
|
5
5
|
logger.level = Logger::WARN
|
6
6
|
|
7
|
-
PuppetValidator.set :puppet_versions, Dir.glob('*').select {|f| File.symlink? f and File.readlink(f) == '.' }
|
8
7
|
PuppetValidator.set :root, File.dirname(__FILE__)
|
9
8
|
PuppetValidator.set :logger, logger
|
10
9
|
|
@@ -16,7 +15,6 @@ PuppetValidator.set :disabled_lint_checks, ['80chars']
|
|
16
15
|
# Protect from cross site request forgery. With this set, code may be
|
17
16
|
# submitted for validation by the website only.
|
18
17
|
#
|
19
|
-
# Note: This will currently break multiple version validation.
|
20
18
|
PuppetValidator.set :csrf, false
|
21
19
|
|
22
20
|
# Provide the option to generate relationship graphs from validated code.
|
data/lib/puppet-validator.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'logger'
|
3
3
|
require 'sinatra/base'
|
4
|
-
require 'puppet'
|
5
|
-
require 'puppet/parser'
|
6
|
-
require 'puppet-lint'
|
7
|
-
|
8
|
-
require 'graphviz'
|
9
4
|
require 'nokogiri'
|
10
5
|
require 'cgi'
|
6
|
+
require 'uri'
|
7
|
+
require 'open-uri'
|
11
8
|
|
12
|
-
# something like 3,000 lines of code
|
13
|
-
|
14
|
-
CONTEXT = 3
|
9
|
+
MAXSIZE = 100000 # something like 3,000 lines of code
|
10
|
+
CONTEXT = 3 # how many lines of code around an error should we highlight?
|
15
11
|
|
16
12
|
class PuppetValidator < Sinatra::Base
|
13
|
+
require 'puppet-validator/validators'
|
14
|
+
require 'puppet-validator/helpers'
|
15
|
+
|
17
16
|
set :logging, true
|
18
17
|
set :strict, true
|
19
18
|
|
@@ -25,6 +24,7 @@ class PuppetValidator < Sinatra::Base
|
|
25
24
|
if settings.csrf
|
26
25
|
session[:csrf] ||= SecureRandom.hex(32)
|
27
26
|
response.set_cookie 'authenticity_token', {
|
27
|
+
:path => '/',
|
28
28
|
:value => session[:csrf],
|
29
29
|
:expires => Time.now + (60 * 60 * 24),
|
30
30
|
}
|
@@ -34,16 +34,6 @@ class PuppetValidator < Sinatra::Base
|
|
34
34
|
def initialize(app=nil)
|
35
35
|
super(app)
|
36
36
|
|
37
|
-
Puppet.initialize_settings rescue nil
|
38
|
-
Puppet.settings[:app_management] = true if Gem::Version.new(Puppet.version) >= Gem::Version.new('4.3.2')
|
39
|
-
|
40
|
-
# set up the base environment
|
41
|
-
Puppet.push_context(Puppet.base_context(Puppet.settings), 'Setup for Puppet Validator') rescue nil
|
42
|
-
|
43
|
-
# disable as much disk access as possible
|
44
|
-
Puppet::Node::Facts.indirection.terminus_class = :memory
|
45
|
-
Puppet::Node.indirection.cache_class = nil
|
46
|
-
|
47
37
|
# make sure that all the settings we expect are defined.
|
48
38
|
[:disabled_lint_checks, :puppet_versions, :csrf].each do |name|
|
49
39
|
next if settings.respond_to? name
|
@@ -68,175 +58,230 @@ class PuppetValidator < Sinatra::Base
|
|
68
58
|
end
|
69
59
|
end
|
70
60
|
|
71
|
-
# put
|
72
|
-
settings.puppet_versions = settings.puppet_versions.sort_by { |v| Gem::Version.new(v) }.reverse
|
61
|
+
# put all installed Puppet versions in reverse semver order
|
62
|
+
#settings.puppet_versions = settings.puppet_versions.sort_by { |v| Gem::Version.new(v) }.reverse
|
63
|
+
settings.puppet_versions = Gem::Specification.all.select {|g| g.name == 'puppet' }.collect {|g| g.version.to_s }
|
64
|
+
|
65
|
+
settings.logger.error "Please gem install one or more Puppet versions." if settings.puppet_versions.empty?
|
73
66
|
|
74
67
|
end
|
75
68
|
|
76
69
|
get '/' do
|
77
|
-
@versions =
|
70
|
+
@versions = settings.puppet_versions
|
71
|
+
@disabled = settings.disabled_lint_checks
|
72
|
+
# loads lint into global namespace, but I don't see an alternative
|
73
|
+
@checks = PuppetValidator::Validators::Lint.all_checks
|
74
|
+
|
75
|
+
erb :index
|
76
|
+
end
|
77
|
+
|
78
|
+
get '/load/referer' do
|
79
|
+
redirect "/load/#{request.referer}"
|
80
|
+
end
|
81
|
+
|
82
|
+
get '/load/*' do
|
83
|
+
location = params[:splat].first.sub(/(https?:)\/\/?/, '\1//')
|
84
|
+
logger.info "Loading code from: #{location}"
|
85
|
+
|
86
|
+
uri = location.downcase.start_with?('http') ? URI.parse(location) : URI.parse("https://#{location}")
|
87
|
+
|
88
|
+
case uri.host
|
89
|
+
when 'gist.github.com'
|
90
|
+
path = uri.path.end_with?('/raw') ? uri : "#{uri}/raw"
|
91
|
+
|
92
|
+
when 'pastebin.com', 'hastebin.com'
|
93
|
+
path = uri.path.start_with?('/raw') ? uri : "#{uri.scheme}://#{uri.host}/raw#{uri.path}"
|
94
|
+
|
95
|
+
else
|
96
|
+
path = nil
|
97
|
+
logger.info "Unrecognized paste service: #{uri}"
|
98
|
+
end
|
99
|
+
|
100
|
+
@versions = settings.puppet_versions
|
78
101
|
@disabled = settings.disabled_lint_checks
|
79
|
-
|
102
|
+
# loads lint into global namespace, but I don't see an alternative
|
103
|
+
@checks = PuppetValidator::Validators::Lint.all_checks
|
104
|
+
@location = location
|
105
|
+
|
106
|
+
if path
|
107
|
+
@code = sanitize_code(open(path).read) rescue nil
|
108
|
+
end
|
80
109
|
|
81
110
|
erb :index
|
82
111
|
end
|
83
112
|
|
113
|
+
# The all-in-one blob that renders via an erb page
|
84
114
|
post '/validate' do
|
85
115
|
logger.info "Validating code from #{request.ip}."
|
86
116
|
logger.debug "validating #{request.ip}: #{params['code']}"
|
87
117
|
|
88
|
-
|
89
|
-
|
90
|
-
frag = Nokogiri::HTML.fragment(params['code'])
|
91
|
-
unless frag.elements.empty?
|
92
|
-
logger.warn 'HTML code found in validation string'
|
93
|
-
frag.elements.each { |elem| logger.debug "HTML: #{elem.to_s}" }
|
94
|
-
params['code'] = CGI.escapeHTML(params['code'])
|
118
|
+
if params.include? 'load'
|
119
|
+
redirect "/load/#{params['location']}"
|
95
120
|
end
|
96
121
|
|
97
|
-
|
98
|
-
|
99
|
-
lint = lint(params['code'], params['checks']) if params['lint'] == 'on'
|
100
|
-
lint ||= {} # but make sure we have a data object to iterate
|
122
|
+
validate_request!
|
123
|
+
sanitize_code! # make code safe for re-rendering
|
101
124
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
@column = result[:pos]
|
108
|
-
@lint_warnings = ! lint.empty?
|
125
|
+
PuppetValidator.run_in_process do
|
126
|
+
if params.include? 'relationships' and settings.graph
|
127
|
+
syntax = PuppetValidator::Validators::Syntax.new(settings)
|
128
|
+
results = syntax.validate(params['code'])
|
129
|
+
results[:status] ? syntax.render! : results[:message]
|
109
130
|
|
110
|
-
# initial highlighting for the potential syntax error
|
111
|
-
if @line
|
112
|
-
start = [@line - CONTEXT, 1].max
|
113
|
-
initial = {"#{start}-#{@line}" => nil}
|
114
131
|
else
|
115
|
-
|
132
|
+
@result = validate_all
|
133
|
+
@result[:code] = params['code']
|
134
|
+
|
135
|
+
erb :result
|
116
136
|
end
|
137
|
+
end
|
138
|
+
end
|
117
139
|
|
118
|
-
|
119
|
-
@highlights = lint.inject(initial) do |acc, item|
|
120
|
-
acc.merge({item[:line] => "#{item[:kind].upcase}: #{item[:message]}"})
|
121
|
-
end.to_json
|
140
|
+
################### API v0 endpoints ###################
|
122
141
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
142
|
+
post '/api/v0/validate' do
|
143
|
+
validate_request!
|
144
|
+
|
145
|
+
PuppetValidator.run_in_process do
|
146
|
+
validate_all.to_json
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
post '/api/v0/validate/syntax' do
|
151
|
+
validate_request!
|
152
|
+
|
153
|
+
PuppetValidator.run_in_process do
|
154
|
+
syntax = PuppetValidator::Validators::Syntax.new(settings)
|
155
|
+
syntax.validate(params['code']).to_json
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
post '/api/v0/validate/relationships' do
|
160
|
+
validate_request!
|
161
|
+
halt 403, 'Graph generation disabled.' unless settings.graph
|
162
|
+
|
163
|
+
PuppetValidator.run_in_process do
|
164
|
+
syntax = PuppetValidator::Validators::Syntax.new(settings)
|
165
|
+
|
166
|
+
# need to prebuild the catalog first
|
167
|
+
results = syntax.validate(params['code'])
|
168
|
+
# return either an SVG or the error message
|
169
|
+
results[:status] ? syntax.render! : results[:message]
|
128
170
|
end
|
129
171
|
|
130
|
-
erb :result
|
131
172
|
end
|
132
173
|
|
174
|
+
post '/api/v0/validate/lint' do
|
175
|
+
validate_request!
|
176
|
+
|
177
|
+
PuppetValidator.run_in_process do
|
178
|
+
linter = PuppetValidator::Validators::Lint.new(settings)
|
179
|
+
linter.validate(params['code']).to_json
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
post '/api/v0/validate/rspec' do
|
184
|
+
validate_request!
|
185
|
+
|
186
|
+
PuppetValidator.run_in_process do
|
187
|
+
rspec = PuppetValidator::Validators::Rspec.new(settings)
|
188
|
+
rspec.validate(params['code'], params['spec']).to_json
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#######################################################
|
193
|
+
|
133
194
|
not_found do
|
134
195
|
halt 404, "You shall not pass! (page not found)\n"
|
135
196
|
end
|
136
197
|
|
137
198
|
helpers do
|
138
199
|
|
139
|
-
def
|
200
|
+
def validate_request!
|
201
|
+
csrf_safe!
|
202
|
+
check_size_limit!
|
203
|
+
end
|
204
|
+
|
205
|
+
def csrf_safe!
|
140
206
|
return true unless settings.csrf
|
141
207
|
if session[:csrf] == params['_csrf'] && session[:csrf] == request.cookies['authenticity_token']
|
142
208
|
true
|
143
209
|
else
|
144
|
-
logger.warn 'CSRF attempt detected.'
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
def validate(data)
|
150
|
-
begin
|
151
|
-
Puppet[:code] = data
|
152
|
-
|
153
|
-
if Puppet::Node::Environment.respond_to?(:create)
|
154
|
-
validation_environment = Puppet::Node::Environment.create(:production, [])
|
155
|
-
validation_environment.check_for_reparse
|
156
|
-
else
|
157
|
-
validation_environment = Puppet::Node::Environment.new(:production)
|
158
|
-
end
|
159
|
-
|
160
|
-
validation_environment.known_resource_types.clear
|
210
|
+
logger.warn 'CSRF attempt detected. Ensure that server time is correct.'
|
211
|
+
logger.debug "session: #{session[:csrf]}"
|
212
|
+
logger.debug " param: #{params['_csrf']}"
|
213
|
+
logger.debug " cookie: #{request.cookies['authenticity_token']}"
|
161
214
|
|
162
|
-
|
163
|
-
rescue => detail
|
164
|
-
logger.warn detail.message
|
165
|
-
err = {:status => false, :message => detail.message}
|
166
|
-
err[:line] = detail.line if detail.methods.include? :line
|
167
|
-
err[:pos] = detail.pos if detail.methods.include? :pos
|
168
|
-
err
|
215
|
+
halt 403, 'Request validation failed.'
|
169
216
|
end
|
170
217
|
end
|
171
218
|
|
172
|
-
def
|
173
|
-
|
174
|
-
|
175
|
-
logger.info "Disabling checks: #{(puppet_lint_checks - checks).inspect}"
|
176
|
-
|
177
|
-
checks.each do |check|
|
178
|
-
PuppetLint.configuration.send("enable_#{check}")
|
179
|
-
end
|
180
|
-
|
181
|
-
(puppet_lint_checks - checks).each do |check|
|
182
|
-
PuppetLint.configuration.send("disable_#{check}")
|
183
|
-
end
|
184
|
-
else
|
185
|
-
logger.info "Disabling checks: #{settings.disabled_lint_checks.inspect}"
|
186
|
-
|
187
|
-
settings.disabled_lint_checks.each do |check|
|
188
|
-
PuppetLint.configuration.send("disable_#{check}")
|
189
|
-
end
|
190
|
-
end
|
219
|
+
def check_size_limit!
|
220
|
+
content = request.body.read
|
221
|
+
request.body.rewind
|
191
222
|
|
192
|
-
|
193
|
-
|
194
|
-
linter.run
|
195
|
-
linter.print_problems
|
196
|
-
rescue => detail
|
197
|
-
logger.warn detail.message
|
198
|
-
nil
|
223
|
+
if content.size > MAXSIZE
|
224
|
+
halt 403, "Submitted code size is #{content.size}, which is larger than the maximum size of #{MAXSIZE}."
|
199
225
|
end
|
200
226
|
end
|
201
227
|
|
202
|
-
def
|
203
|
-
|
204
|
-
PuppetLint.configuration.checks.map {|check| check.to_s}
|
228
|
+
def sanitize_code!
|
229
|
+
params['code'] = sanitize_code(params['code'])
|
205
230
|
end
|
206
231
|
|
207
|
-
def
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
catalog.remove_resource(catalog.resource("Stage", :main)) rescue nil
|
217
|
-
catalog.remove_resource(catalog.resource("Class", :settings)) rescue nil
|
232
|
+
def sanitize_code(code)
|
233
|
+
frag = Nokogiri::HTML.fragment(code)
|
234
|
+
unless frag.elements.empty?
|
235
|
+
logger.warn 'HTML code found in validation string'
|
236
|
+
frag.elements.each { |elem| logger.debug "HTML: #{elem.to_s}" }
|
237
|
+
code = CGI.escapeHTML(code)
|
238
|
+
end
|
239
|
+
code
|
240
|
+
end
|
218
241
|
|
219
|
-
|
242
|
+
def validate_all
|
243
|
+
syntax = PuppetValidator::Validators::Syntax.new(settings, params['version'])
|
244
|
+
result = syntax.validate(params['code'])
|
220
245
|
|
221
|
-
|
222
|
-
|
246
|
+
# munge the data slightly to make it more consumable
|
247
|
+
result[:version] = params['version']
|
248
|
+
result[:success] = result[:status]
|
249
|
+
result[:status] = result[:status] ? :success : :fail
|
250
|
+
result[:column] = result[:pos]
|
251
|
+
result[:messages] = []
|
223
252
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
253
|
+
# initial highlighting for the potential syntax error
|
254
|
+
if result[:line]
|
255
|
+
line = result[:line]
|
256
|
+
start = [line - CONTEXT, 0].max
|
257
|
+
|
258
|
+
result[:messages] << {
|
259
|
+
:from => [start, 0],
|
260
|
+
:to => [line - 1, result[:column]],
|
261
|
+
:message => result[:message],
|
262
|
+
:severity => 'error',
|
263
|
+
}
|
264
|
+
end
|
232
265
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
266
|
+
# then add all the lint warnings and tooltip
|
267
|
+
if params['lint']
|
268
|
+
linter = PuppetValidator::Validators::Lint.new(settings)
|
269
|
+
lint = linter.validate(params['code'], params['checks'])
|
270
|
+
|
271
|
+
result[:lint_warnings] = ! lint.empty?
|
272
|
+
|
273
|
+
lint.each do |item|
|
274
|
+
line = item[:line]-1;
|
275
|
+
result[:messages] << {
|
276
|
+
:from => [line, 0],
|
277
|
+
:to => [line, 1000],
|
278
|
+
:message => "#{item[:kind].upcase}: #{item[:message]}",
|
279
|
+
:severity => 'warning'
|
280
|
+
}
|
281
|
+
end
|
237
282
|
end
|
238
283
|
|
239
|
-
|
284
|
+
result
|
240
285
|
end
|
241
286
|
|
242
287
|
end
|