diff --git a/app/controllers/api/v2/ansible_inventories_controller.rb b/app/controllers/api/v2/ansible_inventories_controller.rb index 1677ef93d..67000cd78 100644 --- a/app/controllers/api/v2/ansible_inventories_controller.rb +++ b/app/controllers/api/v2/ansible_inventories_controller.rb @@ -99,7 +99,11 @@ def schedule_params def show_inventory(ids_key, condition_key) ids = params.fetch(ids_key, []).uniq - render :json => ForemanAnsible::InventoryCreator.new(Host.where(condition_key => ids)).to_hash.to_json + if Foreman::Cast.to_bool(params[:redact_secrets]) || !User.current.can?(:edit_ansible_variables) + render :json => ForemanAnsible::InventoryCreator.new(Host.where(condition_key => ids)).to_hash_with_secrets_redacted.to_json + else + render :json => ForemanAnsible::InventoryCreator.new(Host.where(condition_key => ids)).to_hash.to_json + end end end end diff --git a/app/controllers/api/v2/ansible_variables_controller.rb b/app/controllers/api/v2/ansible_variables_controller.rb index d1e5b2d4a..261f29dc9 100644 --- a/app/controllers/api/v2/ansible_variables_controller.rb +++ b/app/controllers/api/v2/ansible_variables_controller.rb @@ -24,7 +24,13 @@ def show; end param_group :search_and_pagination, ::Api::V2::BaseController add_scoped_search_description_for(AnsibleVariable) def index - @ansible_variables = resource_scope_for_index + vars = resource_scope_for_index + unless User.current.can?(:edit_ansible_variables) + vars.each do |v| + v.value = v.hidden_value? ? v.hidden_value : v.value + end + end + @ansible_variables = vars end api :DELETE, '/ansible_variables/:id', N_('Deletes Ansible variable') diff --git a/app/graphql/presenters/overriden_ansible_variable_presenter.rb b/app/graphql/presenters/overriden_ansible_variable_presenter.rb index ae4003a76..de322656d 100644 --- a/app/graphql/presenters/overriden_ansible_variable_presenter.rb +++ b/app/graphql/presenters/overriden_ansible_variable_presenter.rb @@ -2,18 +2,33 @@ module Presenters class OverridenAnsibleVariablePresenter attr_reader :ansible_variable - delegate :id, :key, :description, :override?, - :parameter_type, :hidden_value?, :omit, :required, - :validator_type, :validator_rule, :default_value, + delegate :id, :key, :description, + :parameter_type, :omit, :required, + :validator_type, :validator_rule, :ansible_role, :current_value, :to => :ansible_variable + def hidden_value + ansible_variable.hidden_value? + end + + def override + ansible_variable.override? + end def initialize(ansible_variable, override_resolver) @ansible_variable = ansible_variable @override_resolver = override_resolver end + def default_value + ansible_variable.editable_by_user? ? ansible_variable.default_value : '*****' + end + def current_value - @override_resolver.resolve @ansible_variable + resolved = @override_resolver.resolve @ansible_variable + unless resolved.nil? + resolved[:value] = '*****' unless ansible_variable.editable_by_user? + end + resolved end end end diff --git a/app/services/foreman_ansible/ansible_info.rb b/app/services/foreman_ansible/ansible_info.rb index ebc9c88a8..c9eafabc7 100644 --- a/app/services/foreman_ansible/ansible_info.rb +++ b/app/services/foreman_ansible/ansible_info.rb @@ -1,16 +1,18 @@ module ForemanAnsible class AnsibleInfo < ::HostInfo::Provider - def host_info - { 'parameters' => ansible_params } + def host_info(redact_secrets = false) + { 'parameters' => ansible_params(redact_secrets) } end - def ansible_params + def ansible_params(redact_secrets = false) variables = AnsibleVariable.where(:ansible_role_id => host.all_ansible_roles.pluck(:id), :override => true) values = variables.values_hash(host) variables.each_with_object({}) do |var, memo| value = values[var] - memo[var.key] = value unless value.nil? + unless value.nil? + memo[var.key] = redact_secrets && var.hidden_value? ? var.hidden_value : value + end memo end end diff --git a/app/services/foreman_ansible/inventory_creator.rb b/app/services/foreman_ansible/inventory_creator.rb index 4eca5c83f..fc6a7b2f8 100644 --- a/app/services/foreman_ansible/inventory_creator.rb +++ b/app/services/foreman_ansible/inventory_creator.rb @@ -19,28 +19,32 @@ def initialize(hosts, template_invocation = nil) # more advanced cases). Therefore we have only the 'all' group # with all hosts. def to_hash + to_hash_with_secrets_redacted(false) + end + + def to_hash_with_secrets_redacted(redact_secrets = true) hosts = @hosts.map(&:name) { 'all' => { 'hosts' => hosts, 'vars' => template_inputs(@template_invocation) }, - '_meta' => { 'hostvars' => hosts_vars } } + '_meta' => { 'hostvars' => hosts_vars(redact_secrets) } } end - def hosts_vars + def hosts_vars(redact_secrets = false) hosts.reduce({}) do |hash, host| hash.update( - host.name => host_vars(host) + host.name => host_vars(host, redact_secrets) ) end end - def host_vars(host) + def host_vars(host, redact_secrets = false) { 'foreman' => reduced_host_info(host).fetch('parameters', {}), 'foreman_ansible_roles' => host_roles(host) }.merge(connection_params(host)). merge(host_params(host)). - merge(ansible_params(host)) + merge(ansible_params(host, redact_secrets)) end def connection_params(host) @@ -62,8 +66,8 @@ def host_roles(host) host.all_ansible_roles.map(&:name) end - def ansible_params(host) - ForemanAnsible::AnsibleInfo.new(host).ansible_params + def ansible_params(host, redact_secrets = false) + ForemanAnsible::AnsibleInfo.new(host).ansible_params(redact_secrets) end def reduced_host_info(host) diff --git a/app/views/ansible_roles/import.html.erb b/app/views/ansible_roles/import.html.erb index 90d140b53..457d29a5b 100644 --- a/app/views/ansible_roles/import.html.erb +++ b/app/views/ansible_roles/import.html.erb @@ -1,6 +1,5 @@ <% title _("Changed Ansible roles") %> <%= webpacked_plugins_js_for :foreman_ansible %> -<%= webpacked_plugins_css_for :foreman_ansible %> <%= react_component( diff --git a/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb b/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb index e9ef4b54c..fa71cb961 100644 --- a/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb +++ b/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb @@ -1,5 +1,4 @@ <%= webpacked_plugins_js_for :foreman_ansible %> -<%= webpacked_plugins_css_for :foreman_ansible %>
<% class_name = f.object.is_a?(Hostgroup) ? 'Hostgroup' : 'Host' %> diff --git a/app/views/foreman_ansible/job_templates/convert_to_rhel.erb b/app/views/foreman_ansible/job_templates/convert_to_rhel.erb index 7819bfdf1..51d7b64f4 100644 --- a/app/views/foreman_ansible/job_templates/convert_to_rhel.erb +++ b/app/views/foreman_ansible/job_templates/convert_to_rhel.erb @@ -27,6 +27,8 @@ kind: job_template %> --- - hosts: all + environment: + CONVERT2RHEL_THROUGH_FOREMAN: 1 tasks: - name: Install convert2rhel ansible.builtin.package: diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/index.js b/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/index.js index 9b737246c..ebc96ba96 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/index.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/index.js @@ -9,7 +9,10 @@ import AnsibleHostInventory from './AnsibleHostInventory'; import ErrorState from '../../../ErrorState'; const WrappedAnsibleHostInventory = ({ hostId }) => { - const params = useMemo(() => ({ params: { host_ids: [hostId] } }), [hostId]); + const params = useMemo( + () => ({ params: { host_ids: [hostId], redact_secrets: true } }), + [hostId] + ); const url = hostId && foremanUrl('/ansible/api/ansible_inventories/hosts'); const { response: inventory, status } = useAPI('get', url, params); diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js index 4864c2601..18f208a01 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js @@ -1,4 +1,5 @@ import React from 'react'; +import { TextInput } from '@patternfly/react-core'; import { TimesIcon, CheckIcon } from '@patternfly/react-icons'; import { sprintf, translate as __ } from 'foremanReact/common/I18n'; @@ -22,6 +23,21 @@ export const formatValue = variable => { ? variable.currentValue.value : variable.defaultValue; + if (variable.hiddenValue) { + return ( + + ); + } + switch (variable.parameterType) { case 'boolean': return value ? : ; diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js index 7ccd4b3d8..10fd1c1ad 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js @@ -36,6 +36,7 @@ const withFqdnOverride = canEdit => ({ validatorType: '', validatorRule: null, required: false, + hiddenValue: false, lookupValues: { nodes: [ { @@ -70,6 +71,7 @@ const withDomainOverride = canEdit => ({ validatorType: '', validatorRule: null, required: false, + hiddenValue: false, lookupValues: { nodes: [], }, @@ -142,6 +144,7 @@ export const mocks = [ validatorType: 'list', validatorRule: 'a,b,c', required: true, + hiddenValue: false, lookupValues: { nodes: [ { @@ -170,6 +173,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: false, lookupValues: { nodes: [], }, @@ -190,6 +194,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: false, lookupValues: { nodes: [], }, @@ -215,6 +220,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: true, lookupValues: { nodes: [], }, @@ -240,6 +246,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: false, lookupValues: { nodes: [], }, @@ -260,6 +267,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: true, lookupValues: { nodes: [], }, @@ -282,6 +290,7 @@ export const mocks = [ validatorType: '', validatorRule: null, required: false, + hiddenValue: true, lookupValues: { nodes: [], }, diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.test.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.test.js index a1e28f722..36ebebdf5 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.test.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.test.js @@ -70,4 +70,20 @@ describe('AnsibleVariableOverrides', () => { const actions = screen.queryAllByRole('button', { name: 'Actions' }); expect(actions).toHaveLength(0); }); + it('should hide hidden values', async () => { + const { container } = render( + + ); + await waitFor(tick); + expect(screen.getByText('ellipse')).toBeInTheDocument(); + expect(screen.getByText('sun')).toBeInTheDocument(); + expect(screen.getByText('moon')).toBeInTheDocument(); + // number of hidden variables + 1 for pagination input + expect(container.getElementsByTagName('input')).toHaveLength(3 + 1); + }); }); diff --git a/webpack/graphql/queries/hostVariableOverrides.gql b/webpack/graphql/queries/hostVariableOverrides.gql index 69039008c..0a99dc995 100644 --- a/webpack/graphql/queries/hostVariableOverrides.gql +++ b/webpack/graphql/queries/hostVariableOverrides.gql @@ -18,6 +18,7 @@ query($id: String!, $match: String, $first: Int, $last: Int) { validatorType validatorRule required + hiddenValue lookupValues(match: $match) { nodes { id