Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow load_paths in safe mode with sanitization #50

Merged
merged 9 commits into from
Nov 14, 2016

Conversation

bkeepers
Copy link
Contributor

load_paths is currently only supported in safe mode. This enables it all the time, but sanitizes the paths with Jekyll.sanitized_path in safe mode to ensure all paths are relative to the source directory. This also adds support for globbing (e.g. **/*/node_modules to add node modules and all transient dependencies to the load path).

Having multiple paths in the sass load path is really helpful when using package managers like bower or NPM. For example:

sass:
  load_paths:
  - bower_components
  - **/*/node_modules

The motivation for this change is so I can use the latest version of primer on a jekyll site.

/cc @jonrohan

@bkeepers
Copy link
Contributor Author

I should have looked at open PRs. It looks like #45 does something similar, but allowing multiple values for sass_dir. Either one of these solutions would work for me.

The globbing in this PR is a nice feature, but not absolutely necessary. I could get around not having it by specifying each nested node_modules directory manually,.

/cc @benbalter @parkr @spudowiar

# Expand file globs (e.g. `node_modules/*/node_modules` )
paths = paths.map { |path| Dir.glob(path) }.flatten.uniq

paths.select { |path| File.directory?(path) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this line and line 82 be combined into one string rather than re-assigning paths? Thus paths.map { }.flatten.uniq.select { }.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changed a bit in e5c28a5 and 7faa098. Let me know if you want me to try to chain these calls together more.

@bkeepers
Copy link
Contributor Author

Any idea what's going on with the tests? They're all passing for me locally, but getting some weird errors on Travis:

  1) Jekyll::Converters::Scss when building configurations in safe mode forces load_paths to be just the local load path
     Failure/Error: Jekyll::Site.new(site_configuration)

     TypeError:
       can't create instance of singleton class
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:428:in `new'
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:428:in `block in instantiate_subclasses'
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:427:in `map'
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:427:in `instantiate_subclasses'
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:81:in `setup'
     # /home/travis/.rvm/gems/ruby-2.3.0/gems/jekyll-2.5.3/lib/jekyll/site.rb:41:in `initialize'
     # ./spec/scss_converter_spec.rb:5:in `new'
     # ./spec/scss_converter_spec.rb:5:in `block (2 levels) in <top (required)>'
     # ./spec/scss_converter_spec.rb:85:in `block (4 levels) in <top (required)>'
     # ./spec/scss_converter_spec.rb:96:in `block (4 levels) in <top (required)>'

@parkr
Copy link
Member

parkr commented Jul 10, 2016

This looks great! @jekyll/security, would you mind taking a quick 👀 to ensure this is production-ready? Seems OK, but easier to ask now than later. 😉

Any idea what's going on with the tests?

@bkeepers We should remove the tests for Jekyll 2.5 for future versions of this gem. Ruby 2.3 changed the way singleton classes work and that seems to have caused a serious issue with Jekyll 2.5. It's not supported any longer so let's just nix it.

@parkr
Copy link
Member

parkr commented Jul 10, 2016

@bkeepers #52 fixes the CI issue.

* origin/master: (24 commits)
  Don't need history sections.
  Update history to reflect merge of jekyll#52 [ci skip]
  Don't test Jekyll 2.5 against Ruby 2.3.
  Whoops, they have to be h3's
  Update history to reflect merge of jekyll#46 [ci skip]
  travis: Jekyll 3.1.2
  travis: match rvm versions with jekyll/jekyll
  Release 💎 v1.4.0
  Update history to reflect merge of jekyll#42
  add_charset false by default, but still strip BOM
  Update history to reflect merge of jekyll#39
  Update history to reflect merge of jekyll#41
  Test Jekyll 2 & 3 explicitly
  fix converter spec for jekyll 3
  travis: update to match jekyll-watch
  Travis: use container infra
  Update Gemfile
  Add Jekyll 2 & 3 to test matrix
  Update history to reflect merge of jekyll#40
  Update the version of Sass to be 3.4.x
  ...
@@ -230,4 +230,60 @@ def converter(overrides = {})

end

context "importing from internal libraries" do
let(:internal_library) { source_dir("bower_components/jquery") }
let(:converter) { site.getConverterImpl(Jekyll::Converters::Scss) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will have to be site.find_converter_instance if Jekyll::VERSION >= "3.0"

@parkr
Copy link
Member

parkr commented Jul 10, 2016

@bkeepers 2 more comments above, then LGTM. ☝️

@bkeepers
Copy link
Contributor Author

Thanks for the review, @parkr!

@parkr
Copy link
Member

parkr commented Jul 10, 2016

This LGTM. Thank you! @benbalter, would you mind being my second pair of 👀 on this?

# Expand file globs (e.g. `node_modules/*/node_modules` )
Dir.chdir(@config["source"]) do
paths = paths.map { |path| Dir.glob(path) }.flatten.uniq.
map { |path| File.expand_path(path) }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather we did the Jekyll.sanitized_path after the expanding/globbing. Dir.glob and File.expand_path should be safe after the Jekyll.sanitized_path call, but they might do something weird that I don't know about.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 on that, thanks for the review, @mastahyeti. @bkeepers, would that work for you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably some DOS vectors if we don't sanitize before (.e.g. /**/* would scan the entire file system). Should we do both?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm 👍 on that. Sanitizing shouldn't be a very expensive operation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkeepers Renewed interest in this. Would you mind taking a sec to update this path sanitization?

@bkeepers
Copy link
Contributor Author

@parkr ok, I made updates based on feedback.

(user_sass_load_paths + [sass_dir_relative_to_site_source]).uniq
end.select { |load_path| File.directory?(load_path) }
# Sanitize paths to prevent any attack vectors (.e.g. `/**/*`)
paths.map! { |path| Jekyll.sanitized_path(@config["source"], path) }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if a malicious user set source: ../../../../../password? Aren't we using untrusted user input here to sanitize user input? (Or is that checked further down the stack @parkr?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On GitHub Pages, we override source so no users could do this. Does that mitigate your concerns?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, @config["source"] comes from site.config. A quick solution is to do what Site does:

@source = File.expand_path(@config["source"]).freeze

@bkeepers
Copy link
Contributor Author

@parkr @benbalter anything I can do to get this merged?

Copy link

@benbalter benbalter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My two concerns around source are resolved since source is going to be overridden on any safe implementation. 👍 from me but defer to @parkr in case there's anything I missed.

@parkr
Copy link
Member

parkr commented Nov 14, 2016

@jekyllbot: merge +minor

@jekyllbot jekyllbot merged commit 510da65 into jekyll:master Nov 14, 2016
jekyllbot added a commit that referenced this pull request Nov 14, 2016
@jekyll jekyll locked and limited conversation to collaborators Apr 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants