Accessing SmartProxy and Hostgroup objects in templates with Safemode

Problem:
I am trying to get the environment to not require Safemode to be disabled. I could solve most problems already including a PR for safemode gem, but now I have one final problem and can not find a solution.

I have two similar code snippets which result in the error Safemode doesn't allow to access 'constant' on Hostgroup / SmartProxy. Both working fine when Safemode is disabled.

The snippet for Hostgroups is used to get all hosts of a specific group defined in a host parameter.

etcd_cluster_nodes = Hostgroup.find_by_name(@host.params['etcd_cluster_group']).hosts.map { |h| "http://#{h.ip}:2379"}.join(',')

The snippets for SmartProxy are trying to find the first Smart Proxy with a specific feature enabled.

SmartProxy.with_taxonomy_scope_override(@host.location, @host.organization).with_features('Omaha').first.url
SmartProxy.with_features("Discovery").first.url

Starting from the host I can only access the name or other attributes of a specific Smart Proxy or Hostgroup assigned to the host with the options I found, like host.hostgroup or host.provision_interface.subnet.tftp_proxy.url which is not enough to solve the requirement if I understood correctly.

Expected outcome:
Access to the Smart Proxy or Hostgroup in templates with Safemode enabled

Foreman and Proxy versions:
1.24

Distribution and version:
RHEL 7

Is it possible to simple whitelist with_features using allow_class_method :with_features inside the Jail?
We’d have to make sure this does not allow breaking out of the Jail.

This would be perhaps part of the solution, but I think it complains already about the direct use of SmartProxy and Hostgroup instead of accessing it via host.

Generally we should not allow powerful ActiveRecord methods because this lets user to break the context and find or even change any record they want regardless of their permissions or taxonomy (e.g. unscoped.find(ID)).

What you could do is to create macros like find_hostgroup_by_name or similar but still disallowing more powerful methods like the ones mentioned above. You need to make sure these only search in scope.

1 Like

Dirk, see whether https://github.com/theforeman/foreman/pull/7364 helps in your case. There are now macros load_smart_proxies and load_host_groups where you can specify search conditions. As long as you can find it using our search sytnax, you can load it in the template. We may need to add more attributes to these object Jails, but that is usually trivial.

I think the first example may look like

etcd_cluster_nodes = load_host_groups(search: 'name = "#{@host.params['etcd_cluster_group']}"'.first.hosts.map { |h| "http://#{h.ip}:2379"}.join(',')

Also for complex objects loading, it’s better to add a new method that would do the heavy-lifting and then allow this method to be called in the template. The more people rely on ActiveRecord API and internal names of methods and relations, the bigger the risk of breaking is. In this particular case, allowing with_features in safemode is IMHO OK, as it probably won’t ever change.