Merge pull request #1668 from Shopify/4-0-backports

Backport ruby 3.2 support for liquid 4
This commit is contained in:
Dylan Thacker-Smith
2023-01-11 10:03:57 -05:00
committed by GitHub
15 changed files with 64 additions and 102 deletions
-2
View File
@@ -1,2 +0,0 @@
enabled:
- cla
+22
View File
@@ -0,0 +1,22 @@
name: Contributor License Agreement (CLA)
on:
pull_request_target:
types: [opened, synchronize]
issue_comment:
types: [created]
jobs:
cla:
runs-on: ubuntu-latest
if: |
(github.event.issue.pull_request
&& !github.event.issue.pull_request.merged_at
&& contains(github.event.comment.body, 'signed')
)
|| (github.event.pull_request && !github.event.pull_request.merged)
steps:
- uses: Shopify/shopify-cla-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
cla-token: ${{ secrets.CLA_TOKEN }}
+27
View File
@@ -0,0 +1,27 @@
name: Liquid
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
entry:
- { ruby: "2.7" } # minimum supported
- { ruby: "3.0", rubocop: true } # latest working with rubocop
- { ruby: "3.2" } # latest
name: test (${{ matrix.entry.ruby }})
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.entry.ruby }}
- uses: actions/cache@v1
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('Gemfile') }}
restore-keys: ${{ runner.os }}-gems-
- run: bundle install --jobs=3 --retry=3 --path=vendor/bundle
- run: bundle exec rake test
- name: Run rubocop
if: matrix.entry.rubocop
run: bundle exec rubocop
+1
View File
@@ -4,6 +4,7 @@ AllCops:
Exclude: Exclude:
- 'performance/shopify/*' - 'performance/shopify/*'
- 'pkg/**' - 'pkg/**'
- 'vendor/bundle/**/*'
Metrics/BlockNesting: Metrics/BlockNesting:
Max: 3 Max: 3
-32
View File
@@ -1,32 +0,0 @@
language: ruby
rvm:
- 2.1
- 2.2
- 2.3
- 2.4
- 2.5
- ruby-head
- jruby-head
# - rbx-2
sudo: false
addons:
apt:
packages:
- libgmp3-dev
matrix:
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
install:
- gem install rainbow -v 2.2.1
- bundle install
script: bundle exec rake
notifications:
disable: true
+1 -1
View File
@@ -15,6 +15,6 @@ group :test do
gem 'rubocop', '~> 0.49.0' gem 'rubocop', '~> 0.49.0'
platform :mri do platform :mri do
gem 'liquid-c', github: 'Shopify/liquid-c', ref: '9168659de45d6d576fce30c735f857e597fa26f6' gem 'liquid-c', github: 'Shopify/liquid-c', branch: '4-0-stable'
end end
end end
+5
View File
@@ -1,5 +1,10 @@
# Liquid Change Log # Liquid Change Log
## 4.0.4 / (unreleased)
### Fixed
* Fix ruby 3.2 compatibility by avoiding use of the removed taint API
## 4.0.3 / 2019-03-12 ## 4.0.3 / 2019-03-12
### Fixed ### Fixed
+1 -1
View File
@@ -39,7 +39,7 @@ module Liquid
end end
def escape(input) def escape(input)
CGI.escapeHTML(input.to_s).untaint unless input.nil? CGI.escapeHTML(input.to_s) unless input.nil?
end end
alias_method :h, :escape alias_method :h, :escape
+2 -4
View File
@@ -63,10 +63,7 @@ module Liquid
# :strict will enforce correct syntax. # :strict will enforce correct syntax.
attr_writer :error_mode attr_writer :error_mode
# Sets how strict the taint checker should be. # Deprecated. No longer used. Removed in version 5
# :lax is the default, and ignores the taint flag completely
# :warn adds a warning, but does not interrupt the rendering
# :error raises an error when tainted output is used
attr_writer :taint_mode attr_writer :taint_mode
attr_accessor :default_exception_renderer attr_accessor :default_exception_renderer
@@ -94,6 +91,7 @@ module Liquid
@error_mode ||= :lax @error_mode ||= :lax
end end
# Deprecated. Removed in version 5
def taint_mode def taint_mode
@taint_mode ||= :lax @taint_mode ||= :lax
end end
+1 -24
View File
@@ -84,11 +84,7 @@ module Liquid
context.invoke(filter_name, output, *filter_args) context.invoke(filter_name, output, *filter_args)
end end
obj = context.apply_global_filter(obj) context.apply_global_filter(obj)
taint_check(context, obj)
obj
end end
private private
@@ -120,25 +116,6 @@ module Liquid
parsed_args parsed_args
end end
def taint_check(context, obj)
return unless obj.tainted?
return if Template.taint_mode == :lax
@markup =~ QuotedFragment
name = Regexp.last_match(0)
error = TaintedError.new("variable '#{name}' is tainted and was not escaped")
error.line_number = line_number
error.template_name = context.template_name
case Template.taint_mode
when :warn
context.warnings << error
when :error
raise error
end
end
class ParseTreeVisitor < Liquid::ParseTreeVisitor class ParseTreeVisitor < Liquid::ParseTreeVisitor
def children def children
[@node.name] + @node.filters.flatten [@node.name] + @node.filters.flatten
+1 -1
View File
@@ -1,5 +1,5 @@
# encoding: utf-8 # encoding: utf-8
module Liquid module Liquid
VERSION = "4.0.3".freeze VERSION = "4.0.4".freeze
end end
+1 -1
View File
@@ -26,6 +26,6 @@ Gem::Specification.new do |s|
s.require_path = "lib" s.require_path = "lib"
s.add_development_dependency 'rake', '~> 11.3' s.add_development_dependency 'rake', '~> 13.0'
s.add_development_dependency 'minitest' s.add_development_dependency 'minitest'
end end
+1 -27
View File
@@ -48,7 +48,7 @@ class ProductDrop < Liquid::Drop
end end
def user_input def user_input
"foo".taint "foo"
end end
protected protected
@@ -112,32 +112,6 @@ class DropsTest < Minitest::Test
assert_equal ' ', tpl.render!('product' => ProductDrop.new) assert_equal ' ', tpl.render!('product' => ProductDrop.new)
end end
def test_rendering_raises_on_tainted_attr
with_taint_mode(:error) do
tpl = Liquid::Template.parse('{{ product.user_input }}')
assert_raises TaintedError do
tpl.render!('product' => ProductDrop.new)
end
end
end
def test_rendering_warns_on_tainted_attr
with_taint_mode(:warn) do
tpl = Liquid::Template.parse('{{ product.user_input }}')
context = Context.new('product' => ProductDrop.new)
tpl.render!(context)
assert_equal [Liquid::TaintedError], context.warnings.map(&:class)
assert_equal "variable 'product.user_input' is tainted and was not escaped", context.warnings.first.to_s(false)
end
end
def test_rendering_doesnt_raise_on_escaped_tainted_attr
with_taint_mode(:error) do
tpl = Liquid::Template.parse('{{ product.user_input | escape }}')
tpl.render!('product' => ProductDrop.new)
end
end
def test_drop_does_only_respond_to_whitelisted_methods def test_drop_does_only_respond_to_whitelisted_methods
assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new) assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new) assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new)
+1 -1
View File
@@ -238,7 +238,7 @@ class ParseTreeVisitorTest < Minitest::Test
def traversal(template) def traversal(template)
ParseTreeVisitor ParseTreeVisitor
.for(Template.parse(template).root) .for(Template.parse(template).root)
.add_callback_for(VariableLookup, &:name) .add_callback_for(VariableLookup) { |node| node.name } # rubocop:disable Style/SymbolProc
end end
def visit(template) def visit(template)
-8
View File
@@ -69,14 +69,6 @@ module Minitest
Liquid::Strainer.class_variable_set(:@@global_strainer, original_global_strainer) Liquid::Strainer.class_variable_set(:@@global_strainer, original_global_strainer)
end end
def with_taint_mode(mode)
old_mode = Liquid::Template.taint_mode
Liquid::Template.taint_mode = mode
yield
ensure
Liquid::Template.taint_mode = old_mode
end
def with_error_mode(mode) def with_error_mode(mode)
old_mode = Liquid::Template.error_mode old_mode = Liquid::Template.error_mode
Liquid::Template.error_mode = mode Liquid::Template.error_mode = mode