Skip to content

Commit

Permalink
Merge branch 'master' into Pralishentity_specific_analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
donrestarone authored Jan 29, 2023
2 parents eedbfa4 + b43d050 commit 70526b5
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 25 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/brakeman-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
sudo apt-get update
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3

# Customize the ruby version depending on your needs
- name: Setup Ruby
Expand All @@ -44,6 +44,6 @@ jobs:
# Upload the SARIF file generated in the previous step
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v1
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: output.sarif.json
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
SERVER_IP: ${{ secrets.SERVER_IP }}
BRANCH: ${{ secrets.BRANCH }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install Rbenv
run: |
sudo git clone https://github.com/rbenv/rbenv.git /home/runner/.rbenv
Expand All @@ -54,11 +54,11 @@ jobs:
with:
ruby-version: 2.6.6
bundler-cache: true
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: 14.x
- name: Add public IP to AWS security group
uses: sohelamin/aws-security-group-add-ip-action@master
uses: uxxman/aws-security-group-add-ip-action@patch-1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dokku-clean-review-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Add public IP to AWS security group
uses: sohelamin/aws-security-group-add-ip-action@master
uses: uxxman/aws-security-group-add-ip-action@patch-1
with:
aws-access-key-id: ${{ secrets.DOKKU_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.DOKKU_AWS_SECRET_ACCESS_KEY }}
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/dokku-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ jobs:
if: github.event_name == 'push'
steps:
- name: Cloning repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Add public IP to AWS security group
uses: sohelamin/aws-security-group-add-ip-action@master
uses: uxxman/aws-security-group-add-ip-action@patch-1
with:
aws-access-key-id: ${{ secrets.DOKKU_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.DOKKU_AWS_SECRET_ACCESS_KEY }}
Expand All @@ -44,12 +44,12 @@ jobs:
if: github.event_name == 'pull_request' && github.event.pull_request.state == 'open' && (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' || github.event.action == 'labeled') && contains( github.event.pull_request.labels.*.name, 'deploy-review-app')
steps:
- name: Cloning repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Add public IP to AWS security group
uses: sohelamin/aws-security-group-add-ip-action@master
uses: uxxman/aws-security-group-add-ip-action@patch-1
with:
aws-access-key-id: ${{ secrets.DOKKU_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.DOKKU_AWS_SECRET_ACCESS_KEY }}
Expand Down Expand Up @@ -114,7 +114,7 @@ jobs:
if: github.event_name == 'pull_request' && ((github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'deploy-review-app')) || (github.event.pull_request.state == 'open' && github.event.action == 'unlabeled' && needs.checklabel.outputs.deploy_review_app_removed))
steps:
- name: Add public IP to AWS security group
uses: sohelamin/aws-security-group-add-ip-action@master
uses: uxxman/aws-security-group-add-ip-action@patch-1
with:
aws-access-key-id: ${{ secrets.DOKKU_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.DOKKU_AWS_SECRET_ACCESS_KEY }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -yqq install libxml2-dev libxslt-dev nodejs yarn tzdata less imagemagick libpq-dev postgresql-client jq bc
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set Environment Variables
run: cat ci_env.cfg >> $GITHUB_ENV
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby_version }} # Not needed with a .ruby-version file (2.6.6) but it's good to be clear here
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node_version }}
- name: Fetch schema file before running migration
Expand Down
6 changes: 3 additions & 3 deletions app/helpers/api_forms_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ def map_non_primitive_data_type(form, type, form_properties = {}, is_edit = fals
key = form.object.label.to_sym
case type
when 'file'
options = { required: form_properties.dig(key, 'required') == '1', class: 'form-control', type: 'file', direct_upload: true, onchange: "previewFile(event, '#{key.to_s.parameterize.underscore}_preview')" }
options = { required: form_properties&.dig(key, 'required') == '1', class: 'form-control', type: 'file', direct_upload: true, onchange: "previewFile(event, '#{key.to_s.parameterize.underscore}_preview')" }
form.file_field :attachment, options
when 'richtext'
options = { placeholder: form_properties.dig(key, 'placeholder'), required: form_properties.dig(key, 'required') == '1' }
options[:value] = form_properties.dig(key, 'prepopulate') == '1' || is_edit ? form.object.content : ''
options = { placeholder: form_properties&.dig(key, 'placeholder'), required: form_properties&.dig(key, 'required') == '1' }
options[:value] = form_properties&.dig(key, 'prepopulate') == '1' || is_edit ? form.object.content : ''
form.rich_text_area :content, options
end
end
Expand Down
12 changes: 10 additions & 2 deletions app/mailers/api_action_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@ def send_email(api_action)
mail_to = api_action.email_evaluated
from = "#{Subdomain.current.name}@#{ENV["APP_HOST"]}"
return if mail_to.empty?

@api_action = api_action
@api_resource = api_action.api_resource

if !@api_resource && api_action.meta_data
@meta_data = api_action.meta_data["api_resource"]
@meta_data["namespace"] = ApiNamespace.find_by(id: ApiAction.find(api_action.id).meta_data["api_resource"]["api_namespace_id"])
end

custom_subject = api_action.email_subject_evaluated || if api_action.api_namespace_action then "#{api_action.type} #{api_action.api_namespace_action.api_namespace&.name.pluralize} v#{api_action.api_namespace_action.api_namespace&.version}"
else "#{api_action.type} #{@api_resource.api_namespace.name.pluralize} v#{@api_resource.api_namespace.version}" end

mail(
from: from,
to: mail_to,
subject: api_action.email_subject_evaluated || "#{api_action.type} #{@api_resource.api_namespace.name.pluralize} v#{@api_resource.api_namespace.version}"
subject: custom_subject
)
end
end
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/dynamic_attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def parse_dynamic_attribute(value, context = {})

def attribute_value_string(attribute)
value = public_send(attribute.to_sym)

# decoding special characters that action text encoded
value = Addressable::URI.unencode(value.to_s) if value.is_a? ActionText::RichText

# Deep copy of non-enumerable column like string-type would get passed and the evaluated value would get reflected as change.
value.is_a?(Enumerable) ? JSON.generate(value) : value.to_s.dup
end
Expand Down
4 changes: 3 additions & 1 deletion app/models/concerns/safe_executable_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ class SafeExecutableValidator < ActiveModel::EachValidator
SPLIT_DELIMITERS = ['(', ')', /\s/, '.', /\n/, /(?<!\:)\:(?!\:)/, '#{', '}', '=>', '"', '\'']

def validate_each(record,attribute,value)
keywords = value.to_s.split(Regexp.union(SPLIT_DELIMITERS)).reject(&:blank?)
# decode and unescape string before checking for blacklisted kwywords
keywords = CGI.unescapeHTML(Addressable::URI.unencode(value.to_s)).split(Regexp.union(SPLIT_DELIMITERS)).reject(&:blank?)
blacklisted_keywords_in_attribute = keywords & (BLACKLISTED_KEYWORDS - (options[:skip_keywords] || []))

unless blacklisted_keywords_in_attribute.empty?
record.errors.add(attribute, "contains disallowed keyword: #{blacklisted_keywords_in_attribute.to_s}. Please refactor #{attribute} accordingly")
end
Expand Down
25 changes: 25 additions & 0 deletions app/views/api_action_mailer/send_email.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@
</div>
<% end %>
</div>
<% elsif @api_action.include_api_resource_data && !@api_resource && @meta_data %>
<p>
<b>Errors:</b>
<%= @meta_data["errors"] %>
</p>
<p>
<b>Api namespace:</b>
<%=@meta_data["namespace"]&.name %>
</p>
<p>
<b>Properties:</b>
<%= @meta_data["properties"] %>
</p>
<div class="mb-3">
<% object_fields(@meta_data["properties"]).each do |prop| %>
<div class="d-flex mb-3">
<div class="mr-4">
<%= "#{prop}:" %>
</div>
<div>
<%= @meta_data["properties"][prop] %>
</div>
</div>
<% end %>
</div>
<% end %>
</main>
</body>
Expand Down
2 changes: 1 addition & 1 deletion app/views/comfy/admin/api_namespaces/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
= f.label :requires_authentication
= f.check_box :requires_authentication
.field
= f.label :has_form
= f.label "Renderable (Form, and representation)"
= f.check_box :has_form, checked: @api_namespace.api_form.present?

- unless has_only_uncategorized_access?(current_user.api_accessibility)
Expand Down
8 changes: 4 additions & 4 deletions client/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 12.x
cache: npm
Expand All @@ -33,9 +33,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 12.x
cache: npm
Expand Down
13 changes: 13 additions & 0 deletions test/controllers/admin/comfy/api_resources_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -548,4 +548,17 @@ class Comfy::Admin::ApiResourcesControllerTest < ActionDispatch::IntegrationTest
expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only or delete_access_for_api_resources_only are allowed to perform that action."
assert_equal expected_message, flash[:alert]
end

test "should able to create api_resource if has_form params is set false" do
@api_namespace.has_form = '0';
@api_namespace.save;
payload_as_stringified_json = "{\"age\":26,\"alive\":true,\"last_name\":\"Teng\",\"first_name\":\"Jennifer\"}"

sign_in(@user)
get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id)
assert_response :success
assert_difference('ApiResource.count') do
post api_namespace_resources_url(api_namespace_id: @api_namespace.id), params: { api_resource: { properties: payload_as_stringified_json } }
end
end
end
9 changes: 9 additions & 0 deletions test/fixtures/api_actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ error_api_action_one:
email: [email protected]
api_namespace: one

error_api_action_one_with_api_resource_data:
type: ErrorApiAction
action_type: send_email
include_api_resource_data: true
payload_mapping:
redirect_url:
email: [email protected]
api_namespace: one

error_api_action_two:
type: ErrorApiAction
action_type: redirect
Expand Down
29 changes: 29 additions & 0 deletions test/mailers/api_action_mailer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require "test_helper"

class ApiActionMailerTest < ActionMailer::TestCase
test 'sends email without api_resource if not included in api action' do
@api_action_1 = api_actions(:error_api_action_one)
@api_action_1.update(email_subject: "")
@api_action_2 = ErrorApiAction.create(@api_action_1.attributes.merge(custom_message: @api_action_1.custom_message.to_s, parent_id: @api_action_1.id, meta_data: { api_resource: { errors: "Error Occured!", properties: {"Null"=>"", "Array"=>"", "Number"=>"", "Object"=>{"a"=>"b", "c"=>"d"}, "String"=>"", "Boolean"=>"false"} }, namespace: { name: "Namespace1" } }).except("id", "created_at", "updated_at", "api_namespace_id"))

email = ApiActionMailer.send_email(@api_action_2)
assert_emails 1 do
email.deliver_later
end
refute_includes email.body, @api_action_2.meta_data["api_resource"]["properties"]
assert_equal "#{@api_action_2.type} #{@api_action_2.api_namespace_action&.api_namespace&.name.pluralize} v#{@api_action_2.api_namespace_action&.api_namespace&.version}", email.subject
end

test 'sends email with api_resource if included in api action' do
@api_action_1 = api_actions(:error_api_action_one_with_api_resource_data)
@api_action_1.update(email_subject: "")
@api_action_2 = ErrorApiAction.create(@api_action_1.attributes.merge(custom_message: @api_action_1.custom_message.to_s, parent_id: @api_action_1.id, meta_data: { api_resource: { errors: "Error Occured!", properties: {"Null"=>"", "Array"=>"", "Number"=>"", "Object"=>{"a"=>"b", "c"=>"d"}, "String"=>"", "Boolean"=>"false"} }, namespace: { name: "Namespace1" } }).except("id", "created_at", "updated_at", "api_namespace_id"))

email = ApiActionMailer.send_email(@api_action_2)
assert_emails 1 do
email.deliver_later
end
assert_includes CGI.unescapeHTML(email.body.to_s), @api_action_2.meta_data["api_resource"]["properties"].to_s
assert_equal "#{@api_action_2.type} #{@api_action_2.api_namespace_action&.api_namespace&.name.pluralize} v#{@api_action_2.api_namespace_action&.api_namespace&.version}", email.subject
end
end
18 changes: 17 additions & 1 deletion test/models/concerns/dynamic_attribute_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def initialize(test_column: nil)
assert_equal safe_instance.test_column_evaluated, 'Test 2'
end


test 'should raise invalid record error dynamic field contains unsafe string' do
unsafe_instance = @dummy_class.new(test_column: "Test \#{User.destroy_all}")
refute unsafe_instance.valid?
Expand All @@ -41,6 +40,16 @@ def initialize(test_column: nil)
end
end

test 'should raise invalid record error if dynamic field contains encoded unsafe string' do
unsafe_instance = @dummy_class.new(test_column: "&lt;%=%20eval%20%1+2%20%&gt;")
refute unsafe_instance.valid?
assert_no_difference "User.all.size" do
assert_raises ActiveRecord::RecordInvalid do
unsafe_instance.test_column_evaluated
end
end
end

test 'should support erb syntax' do
api_resource_test = api_resources(:user)
erb_syntax = '<% food = "Ice cream" %>'\
Expand Down Expand Up @@ -106,4 +115,11 @@ def initialize(test_column: nil)
safe_instance = @dummy_class.new(test_column: { test_key: "<%= 1 + 1 %> and \#{2 + 2}" })
assert_equal safe_instance.test_column_evaluated, { test_key: "2 and 4" }.to_json
end

test 'should unescape html and decode uri-encoded characters' do
safe_instance = @dummy_class.new(test_column: ActionText::RichText.new(body: '<a href="<%= 2 and 4 %>">'))
# action text encoded and escaped special characters
assert_equal "<div class=\"trix-content\">\n <a href=\"&lt;%=%202%20and%204%20%&gt;\"></a>\n</div>\n", safe_instance.test_column.to_s
assert_equal "<div class=\"trix-content\">\n <a href=\"4\"></a>\n</div>\n", safe_instance.test_column_evaluated
end
end

0 comments on commit 70526b5

Please sign in to comment.