diff --git a/app/graphql/presenters/overriden_ansible_variable_presenter.rb b/app/graphql/presenters/overriden_ansible_variable_presenter.rb index ae4003a76..b818f8d68 100644 --- a/app/graphql/presenters/overriden_ansible_variable_presenter.rb +++ b/app/graphql/presenters/overriden_ansible_variable_presenter.rb @@ -15,5 +15,9 @@ def initialize(ansible_variable, override_resolver) def current_value @override_resolver.resolve @ansible_variable end + + def hidden_value + hidden_value? + end end end diff --git a/app/services/foreman_ansible/ansible_info.rb b/app/services/foreman_ansible/ansible_info.rb index ebc9c88a8..975afe9e4 100644 --- a/app/services/foreman_ansible/ansible_info.rb +++ b/app/services/foreman_ansible/ansible_info.rb @@ -1,5 +1,7 @@ module ForemanAnsible class AnsibleInfo < ::HostInfo::Provider + HIDDEN_VALUE = '*****'.freeze + def host_info { 'parameters' => ansible_params } end @@ -10,7 +12,8 @@ def ansible_params variables.each_with_object({}) do |var, memo| value = values[var] - memo[var.key] = value unless value.nil? + next memo if value.nil? + memo[var.key] = var.hidden_value? ? HIDDEN_VALUE : value memo end end diff --git a/test/unit/services/ansible_info_test.rb b/test/unit/services/ansible_info_test.rb new file mode 100644 index 000000000..2e7599cfa --- /dev/null +++ b/test/unit/services/ansible_info_test.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'test_plugin_helper' + +class AnsibleInfoTest < ActiveSupport::TestCase + setup do + @host = FactoryBot.create(:host) + @role = FactoryBot.create(:ansible_role) + @host.ansible_roles << @role + end + + test 'masks hidden variable values in ansible_params' do + variable = FactoryBot.create(:ansible_variable, + :ansible_role => @role, + :key => 'secret_var', + :default_value => 'secret_password', + :override => true) + variable.update(:hidden_value => true) + + info = ForemanAnsible::AnsibleInfo.new(@host) + params = info.ansible_params + + assert_equal '*****', params['secret_var'] + end + + test 'does not mask non-hidden variable values' do + variable = FactoryBot.create(:ansible_variable, + :ansible_role => @role, + :key => 'visible_var', + :default_value => 'visible_value', + :override => true) + variable.update(:hidden_value => false) + + info = ForemanAnsible::AnsibleInfo.new(@host) + params = info.ansible_params + + assert_equal 'visible_value', params['visible_var'] + end +end diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js index 15077e8f3..3e988e9ba 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js @@ -18,7 +18,13 @@ export const formatSourceAttr = variable => ? formatSourceLink(variable.currentValue) : __('Default value'); +const HIDDEN_MASK = '*****'; + export const formatValue = variable => { + if (variable.hiddenValue) { + return HIDDEN_MASK; + } + const value = variable.currentValue ? variable.currentValue.value : variable.defaultValue; diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js index 2e54becc2..047427616 100644 --- a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js @@ -31,6 +31,7 @@ const withFqdnOverride = canEdit => ({ key: 'rectangle', path: '/ansible/ansible_variables/1/edit', defaultValue: 17, + hiddenValue: false, parameterType: 'integer', ansibleRoleName: 'test.role', validatorType: '', @@ -65,6 +66,7 @@ const withDomainOverride = canEdit => ({ key: 'circle', path: '/ansible/ansible_variables/2/edit', defaultValue: 'd', + hiddenValue: false, parameterType: 'string', ansibleRoleName: 'test.role', validatorType: '', @@ -137,6 +139,7 @@ export const mocks = [ key: 'bar', path: '/ansible/ansible_variables/11/edit', defaultValue: 'a', + hiddenValue: false, parameterType: 'string', ansibleRoleName: 'test.role', validatorType: 'list', @@ -165,6 +168,7 @@ export const mocks = [ key: 'square', path: '/ansible/ansible_variables/12/edit', defaultValue: true, + hiddenValue: false, parameterType: 'boolean', ansibleRoleName: 'test.role', validatorType: '', @@ -185,6 +189,7 @@ export const mocks = [ key: 'circle', path: '/ansible/ansible_variables/13/edit', defaultValue: 'd', + hiddenValue: false, parameterType: 'string', ansibleRoleName: 'test.role', validatorType: '', @@ -210,6 +215,7 @@ export const mocks = [ key: 'ellipse', path: '/ansible/ansible_variables/14/edit', defaultValue: ['seven', 'eight'], + hiddenValue: false, parameterType: 'array', ansibleRoleName: 'test.role', validatorType: '', @@ -235,6 +241,7 @@ export const mocks = [ key: 'spiral', path: '/ansible/ansible_variables/15/edit', defaultValue: { one: 'one', two: 'two' }, + hiddenValue: false, parameterType: 'hash', ansibleRoleName: 'test.role', validatorType: '', @@ -255,6 +262,7 @@ export const mocks = [ key: 'sun', path: '/ansible/ansible_variables/16/edit', defaultValue: "{ one: 'one', two: 'two' }", + hiddenValue: false, parameterType: 'json', ansibleRoleName: 'test.role', validatorType: '', @@ -277,6 +285,7 @@ export const mocks = [ defaultValue: [ { hosts: 'all', become: 'true', roles: ['foo'] }, ], + hiddenValue: false, parameterType: 'yaml', ansibleRoleName: 'test.role', validatorType: '', diff --git a/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesTableHelper.test.js b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesTableHelper.test.js new file mode 100644 index 000000000..f5136deca --- /dev/null +++ b/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesTableHelper.test.js @@ -0,0 +1,43 @@ +import { formatValue } from '../AnsibleVariableOverridesTableHelper'; + +describe('formatValue', () => { + it('should mask hidden values', () => { + const variable = { + hiddenValue: true, + defaultValue: 'secret_password', + currentValue: null, + parameterType: 'string', + }; + expect(formatValue(variable)).toBe('*****'); + }); + + it('should mask hidden values even when currentValue exists', () => { + const variable = { + hiddenValue: true, + defaultValue: 'default_secret', + currentValue: { value: 'override_secret' }, + parameterType: 'string', + }; + expect(formatValue(variable)).toBe('*****'); + }); + + it('should show defaultValue when not hidden', () => { + const variable = { + hiddenValue: false, + defaultValue: 'visible_value', + currentValue: null, + parameterType: 'string', + }; + expect(formatValue(variable)).toBe('visible_value'); + }); + + it('should show currentValue when not hidden and override exists', () => { + const variable = { + hiddenValue: false, + defaultValue: 'default_value', + currentValue: { value: 'override_value' }, + parameterType: 'string', + }; + expect(formatValue(variable)).toBe('override_value'); + }); +}); diff --git a/webpack/graphql/queries/hostVariableOverrides.gql b/webpack/graphql/queries/hostVariableOverrides.gql index 69039008c..938d6265f 100644 --- a/webpack/graphql/queries/hostVariableOverrides.gql +++ b/webpack/graphql/queries/hostVariableOverrides.gql @@ -13,6 +13,7 @@ query($id: String!, $match: String, $first: Int, $last: Int) { canEdit } defaultValue + hiddenValue parameterType ansibleRoleName validatorType