jekyll-filesystem-jail 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7481a349425be49a0e0aded08ea090c07943ee8a
4
+ data.tar.gz: 1cf55342e19a7e77ac0a7ee0098fe090aa8783d3
5
+ SHA512:
6
+ metadata.gz: 99b3451809cf2840ed4382d62fb2892820624a70318fa4fde2c1e6173f5c962dcd327b01b2f968c7c815413f7d683b640ac6c4f11f5d6becf16d5b96ffa06f58
7
+ data.tar.gz: ce3ce74ecb72dc0eba15a38ebc8a0dabdbd208fa9e3ad2e14b63c4deb3d5aed4e151b1a1ae1a51ce03a6918a94b78944aa6615203cfa676e28d7b0b716d2a2d1
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ script : script/cibuild
3
+ rvm:
4
+ - 2.1
5
+ - 2.0
6
+ - 1.9.3
7
+ notifications:
8
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 GitHub, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ # Jekyll File System Jail
2
+
3
+ How Jekyll accesses your file system (safely).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jekyll-filesystem-adapter'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jekyll-filesystem-adapter
18
+
19
+ ## Usage
20
+
21
+ It's installed with Jekyll by default and accessible via `Jekyll.fs`.
22
+ Any and all plugins utilizing the file system must use Jekyll.fs to
23
+ be considered secure.
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/jekyll/jekyll-filesystem-jail/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
32
+
33
+ # Credit
34
+
35
+ Written by Parker Moore (@parkr).
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jekyll-filesystem-jail/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jekyll-filesystem-jail"
8
+ spec.version = Jekyll::FileSystem::Jail::VERSION
9
+ spec.authors = ["Parker Moore"]
10
+ spec.email = ["parkrmoore@gmail.com"]
11
+ spec.summary = %q{How Jekyll accesses your file system (safely).}
12
+ spec.homepage = "https://github.com/jekyll/jekyll-filesystem-jail"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec", "~> 3.0"
23
+ spec.add_development_dependency "jekyll", "~> 2.0"
24
+ end
@@ -0,0 +1,166 @@
1
+ # encoding: UTF-8
2
+ require "jekyll-filesystem-jail/version"
3
+ require 'fileutils'
4
+
5
+ module Jekyll
6
+ module FileSystem
7
+ class Jail
8
+
9
+ class << self
10
+ def sanitized_path(base_directory, questionable_path)
11
+ clean_path = File.expand_path(questionable_path, "/")
12
+ clean_path.gsub!(/\A\w\:\//, '/')
13
+
14
+ unless clean_path.start_with?(base_directory)
15
+ File.join(base_directory, clean_path)
16
+ else
17
+ clean_path
18
+ end
19
+ end
20
+ end
21
+
22
+ attr_reader :base_dir, :safe, :site
23
+
24
+ def initialize(base_directory, options = {})
25
+ @base_dir = base_directory
26
+ @safe = options.fetch(:safe, false)
27
+ @site = options.fetch(:site, nil)
28
+ end
29
+
30
+ def safe?
31
+ @safe || (@site && @site.safe) || false
32
+ end
33
+
34
+ def sanitized_path(*paths)
35
+ case paths.size
36
+ when 2
37
+ self.class.sanitized_path(*paths)
38
+ when 1
39
+ self.class.sanitized_path(base_dir, paths.pop)
40
+ else
41
+ raise ArgumentError.new("FileSystemAdapter#sanitized_path takes 1 or 2 arguments.")
42
+ end
43
+ end
44
+
45
+ def realpath(questionable_path)
46
+ File.realpath(questionable_path)
47
+ end
48
+
49
+ #
50
+ # Asking Questions
51
+ #
52
+
53
+ def symlink?(path_to_check)
54
+ File.symlink? path_to_check
55
+ end
56
+
57
+ def file?(path_to_check)
58
+ File.file? path_to_check
59
+ end
60
+
61
+ def directory?(path_to_check)
62
+ File.directory? path_to_check
63
+ end
64
+
65
+ def exist?(path_to_check)
66
+ File.exist? path_to_check
67
+ end
68
+
69
+ def file_allowed?(path_to_check)
70
+ !safe? || !symlink?(path_to_check)
71
+ end
72
+
73
+ #
74
+ # Directory Actions
75
+ #
76
+
77
+ def chdir(directory_to_go_to, &block)
78
+ Dir.chdir(directory_to_go_to, &block)
79
+ end
80
+
81
+ def glob(path_to_glob, flags = nil)
82
+ full_path = path_to_glob
83
+ if flags.nil?
84
+ Dir.glob(full_path)
85
+ else
86
+ Dir.glob(full_path, flags)
87
+ end.sort
88
+ end
89
+
90
+ def dir_entries(directory)
91
+ chdir(directory) do
92
+ glob(sanitized_path(directory, '*')).map do |entry|
93
+ relative_to(directory, entry)
94
+ end
95
+ end
96
+ end
97
+
98
+ def full_directory_glob(directory)
99
+ full_path = directory
100
+ Dir.glob(File.join(full_path, "**", "*"))
101
+ end
102
+
103
+ def rm_rf(file_or_files)
104
+ files = Array(file_or_files).map do |path|
105
+ sanitized_path(path)
106
+ end.select do |path|
107
+ exist?(path)
108
+ end
109
+ FileUtils.rm_r(files, { :secure => true })
110
+ end
111
+
112
+ def mkdir_p(dir_to_create)
113
+ directory = dir_to_create
114
+ FileUtils.mkdir_p(directory) unless exist?(directory)
115
+ end
116
+
117
+ #
118
+ # File Actions
119
+ #
120
+
121
+ def read(path, options = {})
122
+ File.open(path, 'rb') do |f|
123
+ if options[:bytes].nil?
124
+ f.read
125
+ else
126
+ f.read options[:bytes]
127
+ end
128
+ end
129
+ end
130
+
131
+ def write(path, content, options = {})
132
+ File.open(path, 'wb') do |f|
133
+ f.write(content)
134
+ end
135
+ end
136
+
137
+ def relative_to(prefix, entry)
138
+ regexp = Regexp.new("")
139
+ if prefix.end_with?("/")
140
+ entry.sub(/\A#{Regexp.escape(prefix)}/, '')
141
+ else
142
+ entry.sub(/\A#{Regexp.escape(prefix)}\//, '')
143
+ end
144
+ end
145
+
146
+ def sanitize_filename(name)
147
+ name.gsub(/[^\w\s-]+/, '')
148
+ .gsub(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2')
149
+ .gsub(/\s+/, '_')
150
+ end
151
+
152
+ def mtime(path)
153
+ File.mtime path
154
+ end
155
+
156
+ def basename(path, suffix = '')
157
+ File.basename(path, suffix)
158
+ end
159
+
160
+ def dirname(path)
161
+ File.dirname(path)
162
+ end
163
+
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,7 @@
1
+ module Jekyll
2
+ module FileSystem
3
+ class Jail
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle install
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec rspec
@@ -0,0 +1,231 @@
1
+ require 'spec_helper'
2
+
3
+ describe(Jekyll::FileSystem::Jail) do
4
+
5
+ context "class methods" do
6
+ let(:base_dir) { source_dir }
7
+ let(:outside_file) { "/etc/passwd" }
8
+ let(:inside_file) { "resume/index.md" }
9
+
10
+ context ".sanitized_path" do
11
+ it "sanitizes a questionable path outside the base directory correctly" do
12
+ expect(described_class.sanitized_path(base_dir, outside_file)).to(
13
+ eql(source_dir('etc', 'passwd'))
14
+ )
15
+ end
16
+
17
+ it "sanitizes a path inside the base directory correctly" do
18
+ expect(described_class.sanitized_path(base_dir, inside_file)).to(
19
+ eql(source_dir('resume', 'index.md'))
20
+ )
21
+ end
22
+ end
23
+ end
24
+
25
+ context "an instance" do
26
+ let(:source) { source_dir }
27
+ let(:safe) { false }
28
+ let(:site) { nil }
29
+ subject do
30
+ described_class.new(source_dir, { safe: safe, site: site })
31
+ end
32
+
33
+ context "#realpath" do
34
+ it "reads the destination of symlinks" do
35
+ expect(subject.realpath(source_dir('symlink.md'))).to eql(source_dir('homepage.md'))
36
+ end
37
+
38
+ it "errors if the file isn't there" do
39
+ expect(->{ subject.realpath(source_dir('non_existent_file.txt')) }).to raise_error
40
+ end
41
+ end
42
+
43
+ context "#symlink?" do
44
+ it "knows that a symlink is a symlink" do
45
+ expect(subject.symlink?('symlink.md')).to be_truthy
46
+ end
47
+
48
+ it "knows that a regular file is not a symlink" do
49
+ expect(subject.symlink?('homepage.md')).to be_falsey
50
+ end
51
+ end
52
+
53
+ context "#file?" do
54
+ it "knows a file is a file" do
55
+ expect(subject.file?('homepage.md')).to be_truthy
56
+ end
57
+
58
+ it "knows a directory is not a file" do
59
+ expect(subject.file?('about')).to be_falsey
60
+ end
61
+
62
+ it "knows a non-existent file is a not a file" do
63
+ expect(subject.file?('non_existent_file.md')).to be_falsey
64
+ end
65
+
66
+ it "prevents traversal outside base directory" do
67
+ expect(subject.file?('/etc/hosts')).to be_falsey
68
+ end
69
+ end
70
+
71
+ context "#directory?" do
72
+ it "knows a file is not a directory" do
73
+ expect(subject.directory?('homepage.md')).to be_falsey
74
+ end
75
+
76
+ it "knows a directory is a directory" do
77
+ expect(subject.directory?('about')).to be_truthy
78
+ end
79
+
80
+ it "knows a non-existent directory is a not a directory" do
81
+ expect(subject.directory?('i-dont-exist')).to be_falsey
82
+ end
83
+
84
+ it "prevents traversal outside base directory" do
85
+ expect(subject.directory?('/etc')).to be_falsey
86
+ end
87
+ end
88
+
89
+ context "#sanitized_path" do
90
+ it "assumes the base path of the instance" do
91
+ expect(subject.sanitized_path('homepage.md')).to start_with(source_dir)
92
+ end
93
+
94
+ it "allows you to put through a base path if you want, too" do
95
+ expect(subject.sanitized_path(tmp_dir, 'homepage.md')).to start_with(tmp_dir)
96
+ end
97
+
98
+ it "errors with more than 2 arguments" do
99
+ expect(->{ subject.sanitized_path(tmp_dir, 'homepage', 'the thing.md') }).to raise_error
100
+ end
101
+ end
102
+
103
+ context "#read" do
104
+ it "reads in an entire existing file" do
105
+ expect(subject.read(source_dir('homepage.md'))).to eql(<<-FILE
106
+ ---
107
+ title: Home Page
108
+ ---
109
+
110
+ Welcome to my homepage!
111
+ FILE
112
+ )
113
+ end
114
+
115
+ it "reads in just some bytes of an existing file" do
116
+ expect(subject.read(source_dir('homepage.md'), { bytes: 5 })).to eql("---\nt")
117
+ end
118
+ end
119
+
120
+ context "#exist?" do
121
+ it "can tell if a file exists on the filesystem" do
122
+ expect(subject.exist?('homepage.md')).to be_truthy
123
+ end
124
+
125
+ it "can tell if a file doesn't exist" do
126
+ expect(subject.exist?('index.md')).to be_falsey
127
+ end
128
+ end
129
+
130
+ context "#glob" do
131
+ it "grabs the right number of files from a directory" do
132
+ expect(subject.glob('about/**/*').size).to eql(2)
133
+ end
134
+
135
+ it "grabs the right files" do
136
+ expect(
137
+ -> {
138
+ subject.chdir(source_dir('about')) do
139
+ subject.glob('about/**/*')
140
+ end
141
+ }.call
142
+ ).to eql(
143
+ %w(hansel.md index.md)
144
+ )
145
+ end
146
+
147
+ it "can grab subdirectories" do
148
+ expect(
149
+ subject.glob('**/*')
150
+ ).to eql(
151
+ %w(about about/hansel.md about/index.md homepage.md symlink.md)
152
+ )
153
+ end
154
+ end
155
+
156
+ context "#dir_entries" do
157
+ it "grabs just the entries in the immediate folder" do
158
+ expect(subject.dir_entries(source_dir)).to eql(
159
+ %w(about homepage.md symlink.md)
160
+ )
161
+ end
162
+ end
163
+
164
+ context "#rm_rf" do
165
+ subject do
166
+ described_class.new(tmp_dir, { safe: safe, site: site })
167
+ end
168
+ let(:all_files) { [tmp_dir('not_exist')] + files_to_create }
169
+ let(:files_to_create) { [tmp_dir('exit'), tmp_dir('exist')] }
170
+ before(:each) do
171
+ FileUtils.touch files_to_create
172
+ end
173
+
174
+ it "deletes only the files that exist" do
175
+ expect(subject.rm_rf(all_files)).to eql(files_to_create)
176
+ end
177
+ end
178
+
179
+ context "#mkdir_p" do
180
+ after(:each) do
181
+ subject.rm_rf('etc')
182
+ end
183
+
184
+ it "creates a folder" do
185
+ expect(subject.mkdir_p('/etc/hosts')).to eql([source_dir('etc/hosts')])
186
+ end
187
+ end
188
+
189
+ context "safe mode turned on" do
190
+ let(:safe) { true }
191
+
192
+ context "#file_allowed?" do
193
+ it "reports that a symlinked file isn't allowed" do
194
+ expect(subject.file_allowed?('symlink.md')).to be_falsey
195
+ end
196
+
197
+ it "reports that a normal file is allowed" do
198
+ expect(subject.file_allowed?('homepage.md')).to be_truthy
199
+ end
200
+ end
201
+
202
+ context "#safe?" do
203
+ it "reports safe mode turned on" do
204
+ expect(subject.safe?).to be_truthy
205
+ end
206
+ end
207
+ end
208
+
209
+ context "safe mode turned off" do
210
+ let(:safe) { false }
211
+
212
+ context "#file_allowed?" do
213
+ it "reports that a symlinked file is allowed" do
214
+ expect(subject.file_allowed?('symlink.md')).to be_truthy
215
+ end
216
+
217
+ it "reports that a normal file is allowed" do
218
+ expect(subject.file_allowed?('homepage.md')).to be_truthy
219
+ end
220
+ end
221
+
222
+ context "#safe" do
223
+ it "reports safe mode turned off" do
224
+ expect(subject.safe?).to be_falsey
225
+ end
226
+ end
227
+ end
228
+
229
+ end
230
+
231
+ end
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Home Page
3
+ ---
4
+
5
+ Welcome to my homepage!
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Home Page
3
+ ---
4
+
5
+ Welcome to my homepage!
@@ -0,0 +1,83 @@
1
+ TEST_DIR = File.dirname(__FILE__)
2
+ PROJECT_DIR = File.dirname(TEST_DIR)
3
+ TMP_DIR = File.expand_path('tmp', PROJECT_DIR)
4
+
5
+ -> {
6
+ require 'fileutils'
7
+ FileUtils.mkdir(TMP_DIR) unless File.directory?(TMP_DIR)
8
+ }.call
9
+
10
+ require File.expand_path('lib/jekyll-filesystem-jail.rb', PROJECT_DIR)
11
+
12
+ RSpec.configure do |config|
13
+ # The settings below are suggested to provide a good initial experience
14
+ # with RSpec, but feel free to customize to your heart's content.
15
+ # These two settings work together to allow you to limit a spec run
16
+ # to individual examples or groups you care about by tagging them with
17
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
18
+ # get run.
19
+ config.filter_run :focus
20
+ config.run_all_when_everything_filtered = true
21
+
22
+ # Many RSpec users commonly either run the entire suite or an individual
23
+ # file, and it's useful to allow more verbose output when running an
24
+ # individual spec file.
25
+ if config.files_to_run.one?
26
+ # Use the documentation formatter for detailed output,
27
+ # unless a formatter has already been configured
28
+ # (e.g. via a command-line flag).
29
+ config.default_formatter = 'doc'
30
+ end
31
+
32
+ # Print the 10 slowest examples and example groups at the
33
+ # end of the spec run, to help surface which specs are running
34
+ # particularly slow.
35
+ config.profile_examples = 10
36
+
37
+ # Run specs in random order to surface order dependencies. If you find an
38
+ # order dependency and want to debug it, you can fix the order by providing
39
+ # the seed, which is printed after each run.
40
+ # --seed 1234
41
+ config.order = :random
42
+
43
+ # Seed global randomization in this process using the `--seed` CLI option.
44
+ # Setting this allows you to use `--seed` to deterministically reproduce
45
+ # test failures related to randomization by passing the same `--seed` value
46
+ # as the one that triggered the failure.
47
+ Kernel.srand config.seed
48
+
49
+ # rspec-expectations config goes here. You can use an alternate
50
+ # assertion/expectation library such as wrong or the stdlib/minitest
51
+ # assertions if you prefer.
52
+ config.expect_with :rspec do |expectations|
53
+ # Enable only the newer, non-monkey-patching expect syntax.
54
+ # For more details, see:
55
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
56
+ expectations.syntax = :expect
57
+ end
58
+
59
+ # rspec-mocks config goes here. You can use an alternate test double
60
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
61
+ config.mock_with :rspec do |mocks|
62
+ # Enable only the newer, non-monkey-patching expect syntax.
63
+ # For more details, see:
64
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
65
+ mocks.syntax = :expect
66
+
67
+ # Prevents you from mocking or stubbing a method that does not exist on
68
+ # a real object. This is generally recommended.
69
+ mocks.verify_partial_doubles = true
70
+ end
71
+
72
+ def test_dir(*files)
73
+ File.join(TEST_DIR, *files)
74
+ end
75
+
76
+ def source_dir(*files)
77
+ test_dir('source', *files)
78
+ end
79
+
80
+ def tmp_dir(*files)
81
+ File.join(TMP_DIR, *files)
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-filesystem-jail
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Parker Moore
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: jekyll
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ description:
70
+ email:
71
+ - parkrmoore@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - jekyll-filesystem-jail.gemspec
83
+ - lib/jekyll-filesystem-jail.rb
84
+ - lib/jekyll-filesystem-jail/version.rb
85
+ - script/bootstrap
86
+ - script/cibuild
87
+ - spec/jekyll_filesystem_adapter_spec.rb
88
+ - spec/source/about/hansel.md
89
+ - spec/source/about/index.md
90
+ - spec/source/homepage.md
91
+ - spec/source/symlink.md
92
+ - spec/spec_helper.rb
93
+ homepage: https://github.com/jekyll/jekyll-filesystem-jail
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.2.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: How Jekyll accesses your file system (safely).
117
+ test_files:
118
+ - spec/jekyll_filesystem_adapter_spec.rb
119
+ - spec/source/about/hansel.md
120
+ - spec/source/about/index.md
121
+ - spec/source/homepage.md
122
+ - spec/source/symlink.md
123
+ - spec/spec_helper.rb