Skip to content

Conversation

@everettbu
Copy link
Contributor

Test 10

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR implements a comprehensive embedding system enhancement that allows administrators to edit category/host relationships for embedding functionality. The changes migrate from a simple site setting-based approach to a robust database-backed system using a new EmbeddableHost model.

Key architectural changes:

  • Database Migration: Moves embeddable hosts from site settings (embeddable_hosts and embed_category) to a dedicated embeddable_hosts table with foreign key relationships to categories
  • Model Enhancement: Introduces EmbeddableHost model with host validation, URL normalization, and category associations
  • Admin Interface: Adds comprehensive admin UI with routes, controllers, components, and templates for managing embeddable hosts
  • REST API: Enhances the REST serializer and adapter system to handle multiple relationships and admin-specific routing
  • Data Flow: Updates embedding logic in TopicEmber.import to use per-host category configuration instead of global settings

Integration with existing codebase:
The changes integrate deeply with Discourse's existing admin infrastructure, following established patterns for admin controllers, Ember.js components, and REST serialization. The embedding functionality connects with the topic creation system, allowing external sites to embed Discourse content while maintaining proper categorization based on the source host. The implementation preserves backward compatibility while enabling more granular control over embedded content organization.

PR Description Notes:

  • The PR body only contains "Test 10" which provides no meaningful description of the changes

Confidence score: 1/5

  • This PR has critical security vulnerabilities and fabricator issues that will cause immediate failures
  • The main concerns are a SQL injection vulnerability in the migration and completely broken test fabricators that will cause widespread test suite failures
  • Files spec/fabricators/category_fabricator.rb and spec/fabricators/embeddable_host_fabricator.rb have swapped content, destroying category fabricators and creating non-functional embeddable host fabricators

35 files reviewed, 15 comments

Edit Code Review Bot Settings | Greptile

const hydrated = obj[k].map(function(id) {
return self._lookupSubType(subType, type, id, root);
});
obj[self.pluralize(subType)] = hydrated || [];
Copy link

Choose a reason for hiding this comment

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

style: the || [] fallback may be unnecessary since obj[k].map() will always return an array

Suggested change
obj[self.pluralize(subType)] = hydrated || [];
obj[self.pluralize(subType)] = hydrated;

SiteSetting.embed_truncate = false
expect(topic.expandable_first_post?).to eq(false)
end
describe 'with an emeddable host' do
Copy link

Choose a reason for hiding this comment

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

syntax: Typo: 'emeddable' should be 'embeddable'

Suggested change
describe 'with an emeddable host' do
describe 'with an embeddable host' do

Comment on lines +4 to +14
def id
object.id
end

def host
object.host
end

def category_id
object.category_id
end
Copy link

Choose a reason for hiding this comment

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

style: These method definitions are redundant. ActiveModel::Serializer automatically creates attribute methods that return object.attribute_name. You can remove these explicit method definitions unless you need custom logic.


actions: {
edit() {
this.set('categoryId', this.get('host.category.id'));
Copy link

Choose a reason for hiding this comment

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

logic: Potential null reference error if host.category is null/undefined. Should add safety check: this.get('host.category')?.id


const host = this.get('host');
host.save(props).then(() => {
host.set('category', Discourse.Category.findById(this.get('categoryId')));
Copy link

Choose a reason for hiding this comment

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

style: The manual category assignment after save may cause synchronization issues. Consider letting the server response handle category updates.

records = val.split("\n")
if records.present?
records.each do |h|
execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES ('#{h}', #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
Copy link

Choose a reason for hiding this comment

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

logic: Critical SQL injection vulnerability - host value #{h} is directly interpolated without escaping. Use parameterized queries instead.

Suggested change
execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES ('#{h}', #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", h, category_id

Comment on lines +1 to 4
Fabricator(:embeddable_host) do
host "eviltrout.com"
category
end
Copy link

Choose a reason for hiding this comment

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

logic: This completely removes all category fabricators and replaces them with an embeddable_host fabricator. This will break all tests that use :category, :diff_category, :happy_category, or :private_category fabricators. The embeddable_host fabricator should be in spec/fabricators/embeddable_host_fabricator.rb instead.

Comment on lines +1 to +27
Fabricator(:category) do
name { sequence(:name) { |n| "Amazing Category #{n}" } }
user
end

Fabricator(:diff_category, from: :category) do
name "Different Category"
user
end

Fabricator(:happy_category, from: :category) do
name 'Happy Category'
slug 'happy'
user
end

Fabricator(:private_category, from: :category) do
transient :group

name 'Private Category'
slug 'private'
user
after_build do |cat, transients|
cat.update!(read_restricted: true)
cat.category_groups.build(group_id: transients[:group].id, permission_type: CategoryGroup.permission_types[:full])
end
end
Copy link

Choose a reason for hiding this comment

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

logic: Critical error: This file should contain EmbeddableHost fabricators, not Category fabricators. The filename indicates this should define fabricators for EmbeddableHost models (which have host and category_id attributes), but instead contains Category model fabricators. This will break tests expecting embeddable_host fabricators.

Suggested change
Fabricator(:category) do
name { sequence(:name) { |n| "Amazing Category #{n}" } }
user
end
Fabricator(:diff_category, from: :category) do
name "Different Category"
user
end
Fabricator(:happy_category, from: :category) do
name 'Happy Category'
slug 'happy'
user
end
Fabricator(:private_category, from: :category) do
transient :group
name 'Private Category'
slug 'private'
user
after_build do |cat, transients|
cat.update!(read_restricted: true)
cat.category_groups.build(group_id: transients[:group].id, permission_type: CategoryGroup.permission_types[:full])
end
end
Fabricator(:embeddable_host) do
host "example.com"
category
end
Fabricator(:embeddable_host_with_path, from: :embeddable_host) do
host "example.com"
path_whitelist "^/articles/"
category
end
Fabricator(:embeddable_host_with_category, from: :embeddable_host) do
host "blog.example.com"
category { Fabricate(:category) }
end

Comment on lines +6 to +7
self.host.sub!(/^https?:\/\//, '')
self.host.sub!(/\/.*$/, '')
Copy link

Choose a reason for hiding this comment

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

logic: Calling sub! on potentially nil host will raise NoMethodError. Add nil check: self.host&.sub!(/^https?:\/\//, '') or ensure host is present first.

Suggested change
self.host.sub!(/^https?:\/\//, '')
self.host.sub!(/\/.*$/, '')
return unless self.host.present?
self.host.sub!(/^https?:\/\//, '')
self.host.sub!(/\/.*$/, '')

Comment on lines 60 to +61
if !(Rails.env.development? && current_user.try(:admin?))
raise Discourse::InvalidAccess.new('embeddable hosts not set') if SiteSetting.embeddable_hosts.blank?
raise Discourse::InvalidAccess.new('invalid referer host') unless SiteSetting.allows_embeddable_host?(request.referer)
raise Discourse::InvalidAccess.new('invalid referer host') unless EmbeddableHost.host_allowed?(request.referer)
Copy link

Choose a reason for hiding this comment

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

logic: The removal of the blank check for embeddable_hosts setting changes the behavior. Previously, if no hosts were configured, embedding would be blocked entirely. Now it only checks if the specific referer host exists in the database. Consider if this maintains the intended security posture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants