foreman_openscap 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/graphql/mutations/oval_contents/delete.rb +9 -0
- data/app/graphql/mutations/oval_policies/delete.rb +9 -0
- data/app/graphql/mutations/oval_policies/update.rb +15 -0
- data/app/graphql/types/oval_check.rb +11 -0
- data/app/graphql/types/oval_content.rb +2 -0
- data/app/graphql/types/oval_policy.rb +3 -0
- data/app/models/concerns/foreman_openscap/host_extensions.rb +0 -6
- data/app/models/concerns/foreman_openscap/oval_facet_hostgroup_extensions.rb +15 -0
- data/app/models/foreman_openscap/oval_content.rb +2 -0
- data/app/services/foreman_openscap/oval/configure.rb +1 -1
- data/app/services/foreman_openscap/oval/setup.rb +5 -5
- data/app/services/foreman_openscap/oval/setup_check.rb +5 -2
- data/db/migrate/20210819143316_drop_unused_tables.rb +6 -0
- data/lib/foreman_openscap/engine.rb +6 -1
- data/lib/foreman_openscap/version.rb +1 -1
- data/package.json +3 -6
- data/test/graphql/mutations/oval_policies/delete_mutation_test.rb +63 -0
- data/test/graphql/queries/oval_content_query_test.rb +29 -0
- data/test/unit/services/hostgroup_overrider_test.rb +1 -1
- data/test/unit/services/oval/setup_check_test.rb +37 -0
- data/webpack/components/ConfirmModal.js +63 -0
- data/webpack/components/ConfirmModal.scss +3 -0
- data/webpack/components/EditableInput.js +157 -0
- data/webpack/components/EditableInput.scss +3 -0
- data/webpack/components/EmptyState.js +4 -1
- data/webpack/components/IndexLayout.js +11 -4
- data/webpack/components/IndexTable/index.js +17 -17
- data/webpack/components/LinkButton.js +26 -0
- data/webpack/components/withDeleteModal.js +51 -0
- data/webpack/components/withLoading.js +21 -3
- data/webpack/graphql/mutations/deleteOvalContent.gql +9 -0
- data/webpack/graphql/mutations/deleteOvalPolicy.gql +9 -0
- data/webpack/graphql/mutations/updateOvalPolicy.gql +14 -0
- data/webpack/graphql/queries/hostgroups.gql +14 -0
- data/webpack/graphql/queries/ovalContent.gql +8 -0
- data/webpack/graphql/queries/ovalContents.gql +3 -0
- data/webpack/graphql/queries/ovalPolicies.gql +3 -0
- data/webpack/helpers/formFieldsHelper.js +63 -0
- data/webpack/helpers/mutationHelper.js +68 -0
- data/webpack/helpers/pathsHelper.js +5 -0
- data/webpack/helpers/toastHelper.js +3 -0
- data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsIndex.js +25 -0
- data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsTable.js +41 -4
- data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsDestroy.fixtures.js +105 -0
- data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsDestroy.test.js +124 -0
- data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.fixtures.js +61 -59
- data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.test.js +29 -8
- data/webpack/routes/OvalContents/OvalContentsIndex/index.js +7 -1
- data/webpack/routes/OvalContents/OvalContentsNew/OvalContentsNew.js +138 -0
- data/webpack/routes/OvalContents/OvalContentsNew/OvalContentsNew.scss +3 -0
- data/webpack/routes/OvalContents/OvalContentsNew/OvalContentsNewHelper.js +73 -0
- data/webpack/routes/OvalContents/OvalContentsNew/__tests__/OvalContentsNew.test.js +104 -0
- data/webpack/routes/OvalContents/OvalContentsNew/index.js +13 -0
- data/webpack/routes/OvalContents/OvalContentsShow/OvalContentsShow.js +62 -0
- data/webpack/routes/OvalContents/OvalContentsShow/OvalContentsShow.test.js +45 -0
- data/webpack/routes/OvalContents/OvalContentsShow/OvalContentsShowHelper.js +0 -0
- data/webpack/routes/OvalContents/OvalContentsShow/index.js +35 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesIndex.js +17 -2
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesTable.js +16 -3
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesDestroy.fixtures.js +101 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesDestroy.test.js +117 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.fixtures.js +57 -41
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.test.js +14 -2
- data/webpack/routes/OvalPolicies/OvalPoliciesIndex/index.js +7 -1
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/DetailsTab.js +85 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/HostgroupsTab.js +49 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/HostgroupsTable.js +38 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShow.js +15 -11
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShowHelper.js +77 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesEdit.fixtures.js +48 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesEdit.test.js +175 -0
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.fixtures.js +28 -1
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.test.js +47 -4
- data/webpack/routes/OvalPolicies/OvalPoliciesShow/index.js +3 -0
- data/webpack/routes/routes.js +14 -0
- data/webpack/testHelper.js +9 -1
- metadata +46 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0deaa4503a6ab004120595983e5b6fac947691d57e7b8da5d38a0aed3316f1a6
|
|
4
|
+
data.tar.gz: 7447310d905705fbf71ca93f1cca7b2314e7d13827e90ce9c3a8b321cfcba411
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 192e4e96375311fbf3225aa5e715eed99797338a8ba2be9d5b19cdf3f49dcae9ff5a78cb0136df175744360dbcc5ffc2ce453058ac31839a71f0373e79fa22cc
|
|
7
|
+
data.tar.gz: 2b231f618e80bc0bd187417328afae0c2b7f4c7a10d0954dc26ff554fd4ad34c67073b252cdc6f86ae6194d9a9d7c53c5c08bb00ba7348d884e334baac82f1fe
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Mutations
|
|
2
|
+
module OvalPolicies
|
|
3
|
+
class Update < UpdateMutation
|
|
4
|
+
graphql_name 'UpdateOvalPolicyMutation'
|
|
5
|
+
description 'Updates an OVAL Policy'
|
|
6
|
+
resource_class ::ForemanOpenscap::OvalPolicy
|
|
7
|
+
|
|
8
|
+
argument :name, String, required: false
|
|
9
|
+
argument :description, String, required: false
|
|
10
|
+
argument :cron_line, String, required: false
|
|
11
|
+
|
|
12
|
+
field :oval_policy, ::Types::OvalPolicy, 'The OVAL policy.', null: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Types
|
|
2
|
+
class OvalCheck < GraphQL::Schema::Object
|
|
3
|
+
description 'A check that contains information about whether a particual prerequisite for OVAL policy deployment is configured correctly'
|
|
4
|
+
|
|
5
|
+
field :id, String, null: false
|
|
6
|
+
field :title, String, null: false
|
|
7
|
+
field :fail_msg, String, null: true
|
|
8
|
+
field :errors, ::Types::RawJson, null: true
|
|
9
|
+
field :result, String, null: false
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -3,6 +3,8 @@ module Types
|
|
|
3
3
|
description 'An OVAL Policy'
|
|
4
4
|
model_class ::ForemanOpenscap::OvalPolicy
|
|
5
5
|
|
|
6
|
+
include ::Types::Concerns::MetaField
|
|
7
|
+
|
|
6
8
|
global_id_field :id
|
|
7
9
|
timestamps
|
|
8
10
|
field :name, String
|
|
@@ -12,6 +14,7 @@ module Types
|
|
|
12
14
|
field :day_of_month, String
|
|
13
15
|
field :cron_line, String
|
|
14
16
|
belongs_to :oval_content, ::Types::OvalContent
|
|
17
|
+
|
|
15
18
|
has_many :hostgroups, ::Types::Hostgroup
|
|
16
19
|
|
|
17
20
|
def self.graphql_definition
|
|
@@ -50,12 +50,6 @@ module ForemanOpenscap
|
|
|
50
50
|
base.scoped_search :on => :id, :rename => :removed_from_policy,
|
|
51
51
|
:only_explicit => true, :operators => ['= '], :ext_method => :search_by_removed_from_policy
|
|
52
52
|
|
|
53
|
-
base.after_update :puppetrun!, :if => ->(host) do
|
|
54
|
-
Setting[:puppetrun] &&
|
|
55
|
-
host.changed.include?('openscap_proxy_id') &&
|
|
56
|
-
(host.individual_puppetclasses + host.parent_classes).pluck(:name).include?(ClientConfig::Puppet.new.puppetclass_name)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
53
|
base.scope :comply_with, lambda { |policy|
|
|
60
54
|
joins(:arf_reports).merge(ArfReport.latest_of_policy(policy)).merge(ArfReport.passed)
|
|
61
55
|
}
|
|
@@ -6,10 +6,25 @@ module ForemanOpenscap
|
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
8
|
has_many :oval_policies, :through => :oval_facet, :class_name => 'ForemanOpenscap::OvalPolicy'
|
|
9
|
+
|
|
10
|
+
scoped_search :relation => :oval_policies,
|
|
11
|
+
:on => :id,
|
|
12
|
+
:rename => :oval_policy_id,
|
|
13
|
+
:complete_value => false,
|
|
14
|
+
:ext_method => :find_by_oval_policy_id,
|
|
15
|
+
:operators => ['= ']
|
|
9
16
|
end
|
|
10
17
|
|
|
11
18
|
def inherited_oval_policies
|
|
12
19
|
find_inherited_policies :oval_policies
|
|
13
20
|
end
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
def find_by_oval_policy_id(_key, operator, value)
|
|
24
|
+
conditions = sanitize_sql_for_conditions(["#{::ForemanOpenscap::HostgroupOvalFacetOvalPolicy.table_name}.oval_policy_id #{operator} ?", value])
|
|
25
|
+
hg_ids = ::ForemanOpenscap::Hostgroup::OvalFacet.joins(:hostgroup_oval_facet_oval_policies).where(conditions).pluck(:hostgroup_id)
|
|
26
|
+
{ :conditions => ::Hostgroup.arel_table[:id].in(hg_ids).to_sql }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
14
29
|
end
|
|
15
30
|
end
|
|
@@ -58,7 +58,7 @@ module ForemanOpenscap
|
|
|
58
58
|
memo.add_check(
|
|
59
59
|
SetupCheck.new(
|
|
60
60
|
:title => (_("Was %s configured successfully?") % item.class.name),
|
|
61
|
-
:fail_msg =>
|
|
61
|
+
:fail_msg => (_("Assign openscap_proxy to %s before proceeding.") % item.name)
|
|
62
62
|
).fail!
|
|
63
63
|
)
|
|
64
64
|
end
|
|
@@ -59,12 +59,12 @@ module ForemanOpenscap
|
|
|
59
59
|
{
|
|
60
60
|
:id => :foreman_ansible_present,
|
|
61
61
|
:title => _("Is foreman_ansible present?"),
|
|
62
|
-
:fail_msg =>
|
|
62
|
+
:fail_msg => _("foreman_ansible plugin not found, please install it before running this action again.")
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
:id => :foreman_scap_client_role_present,
|
|
66
66
|
:title => _("Is theforeman.foreman_scap_client present?"),
|
|
67
|
-
:fail_msg =>
|
|
67
|
+
:fail_msg => @config.ansible_role_missing_msg
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
:id => :foreman_scap_client_vars_present,
|
|
@@ -74,17 +74,17 @@ module ForemanOpenscap
|
|
|
74
74
|
{
|
|
75
75
|
:id => :foreman_scap_client_server_overriden,
|
|
76
76
|
:title => _("Is %s param set to be overriden?") % @config.server_param,
|
|
77
|
-
:fail_msg =>
|
|
77
|
+
:fail_msg => override_msg
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
:id => :foreman_scap_client_port_overriden,
|
|
81
81
|
:title => _("Is %s param set to be overriden?") % @config.port_param,
|
|
82
|
-
:fail_msg =>
|
|
82
|
+
:fail_msg => override_msg
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
:id => :foreman_scap_client_policies_overriden,
|
|
86
86
|
:title => _("Is %s param set to be overriden?") % @config.policies_param,
|
|
87
|
-
:fail_msg =>
|
|
87
|
+
:fail_msg => override_msg
|
|
88
88
|
}
|
|
89
89
|
]
|
|
90
90
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module ForemanOpenscap
|
|
2
2
|
module Oval
|
|
3
3
|
class SetupCheck
|
|
4
|
-
attr_reader :result, :id
|
|
4
|
+
attr_reader :result, :id, :errors
|
|
5
5
|
|
|
6
6
|
def initialize(hash)
|
|
7
7
|
@id = hash[:id]
|
|
@@ -17,6 +17,7 @@ module ForemanOpenscap
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def fail!
|
|
20
|
+
raise 'Cannot fail a check that expects fail message data, use fail_with! method instead' if @fail_msg.respond_to?(:call) && @fail_msg_data.empty?
|
|
20
21
|
@result = :fail
|
|
21
22
|
self
|
|
22
23
|
end
|
|
@@ -39,7 +40,9 @@ module ForemanOpenscap
|
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
def fail_msg
|
|
42
|
-
|
|
43
|
+
return unless failed?
|
|
44
|
+
return @fail_msg.call(@fail_msg_data) if @fail_msg.respond_to?(:call) && @fail_msg_data
|
|
45
|
+
@fail_msg
|
|
43
46
|
end
|
|
44
47
|
|
|
45
48
|
def to_h
|
|
@@ -219,10 +219,15 @@ module ForemanOpenscap
|
|
|
219
219
|
register_global_js_file 'global'
|
|
220
220
|
|
|
221
221
|
register_graphql_query_field :oval_contents, '::Types::OvalContent', :collection_field
|
|
222
|
+
register_graphql_query_field :oval_content, '::Types::OvalContent', :record_field
|
|
222
223
|
register_graphql_query_field :oval_policies, '::Types::OvalPolicy', :collection_field
|
|
223
224
|
register_graphql_query_field :oval_policy, '::Types::OvalPolicy', :record_field
|
|
224
225
|
register_graphql_query_field :cves, '::Types::Cve', :collection_field
|
|
225
226
|
|
|
227
|
+
register_graphql_mutation_field :delete_oval_policy, ::Mutations::OvalPolicies::Delete
|
|
228
|
+
register_graphql_mutation_field :delete_oval_content, ::Mutations::OvalContents::Delete
|
|
229
|
+
register_graphql_mutation_field :update_oval_policy, ::Mutations::OvalPolicies::Update
|
|
230
|
+
|
|
226
231
|
register_facet ForemanOpenscap::Host::OvalFacet, :oval_facet do
|
|
227
232
|
configure_host do
|
|
228
233
|
extend_model ForemanOpenscap::OvalFacetHostExtensions
|
|
@@ -276,7 +281,7 @@ module ForemanOpenscap
|
|
|
276
281
|
|
|
277
282
|
if Gem::Version.new(ForemanRemoteExecution::VERSION) >= Gem::Version.new('1.2.3')
|
|
278
283
|
options[:host_action_button] = true
|
|
279
|
-
oval_options[:host_action_button] = Setting
|
|
284
|
+
oval_options[:host_action_button] = (!::Foreman.in_rake? && ActiveRecord::Base.connection.table_exists?(:settings)) ? (Setting.find_by(:name => 'lab_features')&.value || false) : false
|
|
280
285
|
end
|
|
281
286
|
|
|
282
287
|
RemoteExecutionFeature.register(:foreman_openscap_run_scans, N_("Run OpenSCAP scan"), options)
|
data/package.json
CHANGED
|
@@ -24,23 +24,20 @@
|
|
|
24
24
|
"@theforeman/vendor": ">= 4.13.2"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@apollo/react-testing": "^4.0.0",
|
|
28
27
|
"@babel/core": "^7.7.0",
|
|
29
|
-
"@testing-library/dom": "^
|
|
28
|
+
"@testing-library/dom": "^8.9.1",
|
|
30
29
|
"@testing-library/jest-dom": "^5.11.9",
|
|
31
|
-
"@testing-library/
|
|
32
|
-
"@testing-library/user-event": "^13.1.2",
|
|
30
|
+
"@testing-library/user-event": "^13.2.1",
|
|
33
31
|
"@theforeman/builder": "^8.4.1",
|
|
34
32
|
"@theforeman/eslint-plugin-foreman": "8.4.1",
|
|
35
33
|
"@theforeman/find-foreman": "^8.4.1",
|
|
36
34
|
"@theforeman/stories": "^8.4.1",
|
|
37
|
-
"@theforeman/test": "^8.
|
|
35
|
+
"@theforeman/test": "^8.9.0",
|
|
38
36
|
"@theforeman/vendor-dev": "^8.4.1",
|
|
39
37
|
"babel-eslint": "^10.0.3",
|
|
40
38
|
"eslint": "^6.7.2",
|
|
41
39
|
"jed": "^1.1.1",
|
|
42
40
|
"jest-svg-transformer": "^1.0.0",
|
|
43
|
-
"jest-transform-graphql": "^2.1.0",
|
|
44
41
|
"prettier": "^1.13.5",
|
|
45
42
|
"stylelint": "^9.3.0",
|
|
46
43
|
"stylelint-config-standard": "^18.0.0"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
module Mutations
|
|
4
|
+
module OvalPolicies
|
|
5
|
+
class DeleteMutationTest < ActiveSupport::TestCase
|
|
6
|
+
let(:policy) { FactoryBot.create(:oval_policy, :oval_content => FactoryBot.create(:oval_content)) }
|
|
7
|
+
let(:policy_id) { Foreman::GlobalId.for(policy) }
|
|
8
|
+
let(:variables) do
|
|
9
|
+
{
|
|
10
|
+
id: policy_id,
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
let(:query) do
|
|
14
|
+
<<-GRAPHQL
|
|
15
|
+
mutation DeleteOvalPolicyMutation($id:ID!){
|
|
16
|
+
deleteOvalPolicy(input:{id:$id}) {
|
|
17
|
+
id
|
|
18
|
+
errors {
|
|
19
|
+
message
|
|
20
|
+
path
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
GRAPHQL
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'with admin user' do
|
|
28
|
+
let(:user) { FactoryBot.create(:user, :admin) }
|
|
29
|
+
|
|
30
|
+
test 'should delete oval policy' do
|
|
31
|
+
context = { current_user: user }
|
|
32
|
+
|
|
33
|
+
policy
|
|
34
|
+
|
|
35
|
+
assert_difference('::ForemanOpenscap::OvalPolicy.count', -1) do
|
|
36
|
+
result = ForemanGraphqlSchema.execute(query, variables: variables, context: context)
|
|
37
|
+
assert_empty result['errors']
|
|
38
|
+
assert_empty result['data']['deleteOvalPolicy']['errors']
|
|
39
|
+
assert_equal policy_id, result['data']['deleteOvalPolicy']['id']
|
|
40
|
+
end
|
|
41
|
+
assert_equal user.id, Audit.last.user_id
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'with user with view permissions' do
|
|
46
|
+
setup do
|
|
47
|
+
policy
|
|
48
|
+
@user = setup_user 'view', 'oval_policies'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test 'should not delete oval policy' do
|
|
52
|
+
context = { current_user: @user }
|
|
53
|
+
|
|
54
|
+
assert_difference('ForemanOpenscap::OvalPolicy.count', 0) do
|
|
55
|
+
result = ForemanGraphqlSchema.execute(query, variables: variables, context: context)
|
|
56
|
+
assert_not_empty result['errors']
|
|
57
|
+
assert_includes result['errors'].map { |error| error['message'] }.to_sentence, 'Unauthorized.'
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
module Queries
|
|
4
|
+
class OvalContentQueryTest < GraphQLQueryTestCase
|
|
5
|
+
let(:query) do
|
|
6
|
+
<<-GRAPHQL
|
|
7
|
+
query($id:String!) {
|
|
8
|
+
ovalContent(id: $id) {
|
|
9
|
+
id
|
|
10
|
+
name
|
|
11
|
+
originalFilename
|
|
12
|
+
url
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
GRAPHQL
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
let(:oval_content) { FactoryBot.create(:oval_content) }
|
|
19
|
+
|
|
20
|
+
let(:global_id) { Foreman::GlobalId.for(oval_content) }
|
|
21
|
+
let(:variables) { { id: global_id } }
|
|
22
|
+
let(:data) { result['data']['ovalContent'] }
|
|
23
|
+
|
|
24
|
+
test 'should return OVAL Content' do
|
|
25
|
+
assert_equal global_id, data['id']
|
|
26
|
+
assert_equal oval_content.name, data['name']
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -14,7 +14,7 @@ class HostgroupOverriderTest < ActiveSupport::TestCase
|
|
|
14
14
|
|
|
15
15
|
proxy = FactoryBot.create(:openscap_proxy, :url => 'https://override-keys.example.com:8998')
|
|
16
16
|
|
|
17
|
-
hostgroup = FactoryBot.create(:hostgroup, :
|
|
17
|
+
hostgroup = FactoryBot.create(:hostgroup, :environment => env, :openscap_proxy_id => proxy.id, :puppet => FactoryBot.create(:hostgroup_puppet_facet))
|
|
18
18
|
refute hostgroup.puppetclasses.include? puppet_class
|
|
19
19
|
assert LookupValue.where(:match => "hostgroup=#{hostgroup.to_label}",
|
|
20
20
|
:lookup_key_id => port_param.id,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
class ForemanOpenscap::Oval::SetupCheckTest < ActiveSupport::TestCase
|
|
4
|
+
test 'should show error message with filled in data' do
|
|
5
|
+
check = ::ForemanOpenscap::Oval::SetupCheck.new(
|
|
6
|
+
:id => :test_check,
|
|
7
|
+
:title => _("Will it pass?"),
|
|
8
|
+
:fail_msg => ->(hash) { "There was an error in #{hash[:name]}, you need to #{hash[:action]}" }
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
check.fail_with!(:name => 'your engine', :action => 'run')
|
|
12
|
+
assert_equal 'There was an error in your engine, you need to run', check.fail_msg
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
test 'should show error message when it is a string' do
|
|
16
|
+
msg = "Do not panic"
|
|
17
|
+
check = ::ForemanOpenscap::Oval::SetupCheck.new(
|
|
18
|
+
:id => :test_check,
|
|
19
|
+
:title => _("Will it pass?"),
|
|
20
|
+
:fail_msg => msg
|
|
21
|
+
)
|
|
22
|
+
check.fail!
|
|
23
|
+
assert_equal msg, check.fail_msg
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
test 'should not show error message when check not failed' do
|
|
27
|
+
check = ::ForemanOpenscap::Oval::SetupCheck.new(
|
|
28
|
+
:id => :test_check,
|
|
29
|
+
:title => _("Will it pass?"),
|
|
30
|
+
:fail_msg => 'foo'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assert_nil check.fail_msg
|
|
34
|
+
check.fail!
|
|
35
|
+
assert_not_nil check.fail_msg
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Modal, Button, ModalVariant, Spinner } from '@patternfly/react-core';
|
|
4
|
+
|
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
6
|
+
|
|
7
|
+
import './ConfirmModal.scss';
|
|
8
|
+
|
|
9
|
+
const ConfirmModal = props => {
|
|
10
|
+
const [callMutation, { loading }] = props.prepareMutation();
|
|
11
|
+
|
|
12
|
+
const actions = [
|
|
13
|
+
<Button
|
|
14
|
+
key="confirm"
|
|
15
|
+
variant="primary"
|
|
16
|
+
onClick={() => props.onConfirm(callMutation, props.record.id)}
|
|
17
|
+
isDisabled={loading}
|
|
18
|
+
>
|
|
19
|
+
{__('Confirm')}
|
|
20
|
+
</Button>,
|
|
21
|
+
<Button
|
|
22
|
+
key="cancel"
|
|
23
|
+
variant="link"
|
|
24
|
+
onClick={event => props.onClose()}
|
|
25
|
+
isDisabled={loading}
|
|
26
|
+
>
|
|
27
|
+
{__('Cancel')}
|
|
28
|
+
</Button>,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
if (loading) {
|
|
32
|
+
actions.push(<Spinner key="spinner" size="lg" />);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Modal
|
|
37
|
+
variant={ModalVariant.medium}
|
|
38
|
+
title={props.title}
|
|
39
|
+
isOpen={props.isOpen}
|
|
40
|
+
className="foreman-modal"
|
|
41
|
+
showClose={false}
|
|
42
|
+
actions={actions}
|
|
43
|
+
>
|
|
44
|
+
{props.text}
|
|
45
|
+
</Modal>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
ConfirmModal.propTypes = {
|
|
50
|
+
prepareMutation: PropTypes.func.isRequired,
|
|
51
|
+
onConfirm: PropTypes.func.isRequired,
|
|
52
|
+
record: PropTypes.object,
|
|
53
|
+
onClose: PropTypes.func.isRequired,
|
|
54
|
+
title: PropTypes.string.isRequired,
|
|
55
|
+
isOpen: PropTypes.bool.isRequired,
|
|
56
|
+
text: PropTypes.string.isRequired,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
ConfirmModal.defaultProps = {
|
|
60
|
+
record: null,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default ConfirmModal;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Split,
|
|
7
|
+
SplitItem,
|
|
8
|
+
Spinner,
|
|
9
|
+
FormGroup,
|
|
10
|
+
} from '@patternfly/react-core';
|
|
11
|
+
import {
|
|
12
|
+
TimesIcon,
|
|
13
|
+
CheckIcon,
|
|
14
|
+
PencilAltIcon,
|
|
15
|
+
ExclamationCircleIcon,
|
|
16
|
+
} from '@patternfly/react-icons';
|
|
17
|
+
|
|
18
|
+
import './EditableInput.scss';
|
|
19
|
+
|
|
20
|
+
const EditableInput = props => {
|
|
21
|
+
const [editing, setEditing] = useState(false);
|
|
22
|
+
const [submitting, setSubmitting] = useState(false);
|
|
23
|
+
const [inputValue, setInputValue] = useState(props.value);
|
|
24
|
+
const [error, setError] = useState('');
|
|
25
|
+
const [touched, setTouched] = useState(false);
|
|
26
|
+
|
|
27
|
+
const stopSubmitting = () => setSubmitting(false);
|
|
28
|
+
|
|
29
|
+
const handleSubmit = event => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
onSubmit();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const onFinish = () => {
|
|
35
|
+
setSubmitting(false);
|
|
36
|
+
setEditing(false);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const onSubmit = () => {
|
|
40
|
+
setSubmitting(true);
|
|
41
|
+
props.onConfirm(inputValue, onFinish, stopSubmitting, onError);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const onError = err => {
|
|
45
|
+
setTouched(false);
|
|
46
|
+
setError(err);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const onCancel = () => {
|
|
50
|
+
setInputValue(props.value);
|
|
51
|
+
setEditing(false);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const onChange = value => {
|
|
55
|
+
if (!touched) {
|
|
56
|
+
setTouched(true);
|
|
57
|
+
}
|
|
58
|
+
setInputValue(value);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (!editing) {
|
|
62
|
+
return (
|
|
63
|
+
<Split>
|
|
64
|
+
<SplitItem>{props.value || <i>{__('None provided')}</i>}</SplitItem>
|
|
65
|
+
<SplitItem>
|
|
66
|
+
<Button
|
|
67
|
+
className="inline-edit-icon"
|
|
68
|
+
aria-label={`edit ${props.attrName}`}
|
|
69
|
+
variant="plain"
|
|
70
|
+
onClick={() => setEditing(true)}
|
|
71
|
+
>
|
|
72
|
+
<PencilAltIcon />
|
|
73
|
+
</Button>
|
|
74
|
+
</SplitItem>
|
|
75
|
+
</Split>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const Component = props.component;
|
|
80
|
+
|
|
81
|
+
const shouldValidate = (isTouched, err) => {
|
|
82
|
+
if (!isTouched) {
|
|
83
|
+
return err ? 'error' : 'success';
|
|
84
|
+
}
|
|
85
|
+
return 'noval';
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const valid = shouldValidate(touched, error);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Split>
|
|
92
|
+
<SplitItem>
|
|
93
|
+
<form onSubmit={handleSubmit} className="pf-c-form">
|
|
94
|
+
<FormGroup
|
|
95
|
+
helperTextInvalid={error}
|
|
96
|
+
helperTextInvalidIcon={<ExclamationCircleIcon />}
|
|
97
|
+
validated={valid}
|
|
98
|
+
>
|
|
99
|
+
<Component
|
|
100
|
+
{...props.inputProps}
|
|
101
|
+
type="text"
|
|
102
|
+
aria-label={`${props.attrName} text input`}
|
|
103
|
+
isDisabled={submitting}
|
|
104
|
+
value={inputValue || ''}
|
|
105
|
+
onChange={onChange}
|
|
106
|
+
validated={valid}
|
|
107
|
+
/>
|
|
108
|
+
</FormGroup>
|
|
109
|
+
</form>
|
|
110
|
+
</SplitItem>
|
|
111
|
+
<SplitItem>
|
|
112
|
+
<Button
|
|
113
|
+
aria-label={`submit ${props.attrName}`}
|
|
114
|
+
variant="plain"
|
|
115
|
+
onClick={onSubmit}
|
|
116
|
+
isDisabled={submitting}
|
|
117
|
+
>
|
|
118
|
+
<CheckIcon />
|
|
119
|
+
</Button>
|
|
120
|
+
</SplitItem>
|
|
121
|
+
<SplitItem>
|
|
122
|
+
<Button
|
|
123
|
+
aria-label={`cancel editing ${props.attrName}`}
|
|
124
|
+
variant="plain"
|
|
125
|
+
onClick={onCancel}
|
|
126
|
+
isDisabled={submitting}
|
|
127
|
+
>
|
|
128
|
+
<TimesIcon />
|
|
129
|
+
</Button>
|
|
130
|
+
</SplitItem>
|
|
131
|
+
<SplitItem>
|
|
132
|
+
{submitting && (
|
|
133
|
+
<Spinner
|
|
134
|
+
key="spinner"
|
|
135
|
+
size="lg"
|
|
136
|
+
id={`edit-${props.attrName}-spinner`}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
</SplitItem>
|
|
140
|
+
</Split>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
EditableInput.propTypes = {
|
|
145
|
+
value: PropTypes.string,
|
|
146
|
+
onConfirm: PropTypes.func.isRequired,
|
|
147
|
+
attrName: PropTypes.string.isRequired,
|
|
148
|
+
component: PropTypes.object.isRequired,
|
|
149
|
+
inputProps: PropTypes.object,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
EditableInput.defaultProps = {
|
|
153
|
+
inputProps: {},
|
|
154
|
+
value: '',
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default EditableInput;
|