foreman_openscap 4.1.3 → 4.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/foreman_openscap/policy.css +5 -0
  3. data/app/controllers/api/v2/compliance/oval_contents_controller.rb +72 -0
  4. data/app/controllers/api/v2/compliance/oval_policies_controller.rb +111 -0
  5. data/app/controllers/api/v2/compliance/oval_reports_controller.rb +47 -0
  6. data/app/controllers/concerns/foreman/controller/parameters/oval_content.rb +22 -0
  7. data/app/controllers/concerns/foreman/controller/parameters/oval_policy.rb +22 -0
  8. data/app/controllers/concerns/foreman_openscap/hosts_controller_extensions.rb +1 -1
  9. data/app/graphql/types/cve.rb +17 -0
  10. data/app/graphql/types/oval_content.rb +17 -0
  11. data/app/graphql/types/oval_policy.rb +21 -0
  12. data/app/helpers/arf_reports_helper.rb +7 -24
  13. data/app/helpers/policies_helper.rb +4 -17
  14. data/app/mailers/foreman_openscap/policy_mailer.rb +2 -2
  15. data/app/models/concerns/foreman_openscap/compliance_status_scoped_search.rb +1 -1
  16. data/app/models/concerns/foreman_openscap/data_stream_content.rb +0 -17
  17. data/app/models/concerns/foreman_openscap/host_extensions.rb +11 -11
  18. data/app/models/concerns/foreman_openscap/hostgroup_extensions.rb +3 -5
  19. data/app/models/concerns/foreman_openscap/inherited_policies.rb +11 -0
  20. data/app/models/concerns/foreman_openscap/oval_facet_host_extensions.rb +38 -0
  21. data/app/models/concerns/foreman_openscap/oval_facet_hostgroup_extensions.rb +15 -0
  22. data/app/models/concerns/foreman_openscap/policy_common.rb +75 -0
  23. data/app/models/concerns/foreman_openscap/scap_file_content.rb +24 -0
  24. data/app/models/foreman_openscap/arf_report.rb +2 -2
  25. data/app/models/foreman_openscap/cve.rb +23 -0
  26. data/app/models/foreman_openscap/host/oval_facet.rb +14 -0
  27. data/app/models/foreman_openscap/host_cve.rb +7 -0
  28. data/app/models/foreman_openscap/hostgroup/oval_facet.rb +14 -0
  29. data/app/models/foreman_openscap/hostgroup_oval_facet_oval_policy.rb +6 -0
  30. data/app/models/foreman_openscap/oval_content.rb +26 -0
  31. data/app/models/foreman_openscap/oval_facet_oval_policy.rb +6 -0
  32. data/app/models/foreman_openscap/oval_policy.rb +54 -0
  33. data/app/models/foreman_openscap/oval_status.rb +45 -0
  34. data/app/models/foreman_openscap/policy.rb +10 -73
  35. data/app/models/foreman_openscap/scap_content.rb +1 -0
  36. data/app/models/foreman_openscap/tailoring_file.rb +1 -0
  37. data/app/services/foreman_openscap/client_config/ansible.rb +39 -6
  38. data/app/services/foreman_openscap/client_config/base.rb +5 -1
  39. data/app/services/foreman_openscap/client_config/puppet.rb +2 -1
  40. data/app/services/foreman_openscap/config_name_service.rb +1 -1
  41. data/app/services/foreman_openscap/hostgroup_overrider.rb +2 -24
  42. data/app/services/foreman_openscap/hostgroup_overrider_common.rb +28 -0
  43. data/app/services/foreman_openscap/lookup_key_overrider.rb +30 -62
  44. data/app/services/foreman_openscap/lookup_key_overrides_common.rb +63 -0
  45. data/app/services/foreman_openscap/oval/check_collection.rb +45 -0
  46. data/app/services/foreman_openscap/oval/configure.rb +80 -0
  47. data/app/services/foreman_openscap/oval/cves.rb +41 -0
  48. data/app/services/foreman_openscap/oval/setup.rb +93 -0
  49. data/app/services/foreman_openscap/oval/setup_check.rb +55 -0
  50. data/app/services/foreman_openscap/oval/sync_oval_contents.rb +42 -0
  51. data/app/views/api/v2/compliance/oval_contents/base.json.rabl +6 -0
  52. data/app/views/api/v2/compliance/oval_contents/create.json.rabl +3 -0
  53. data/app/views/api/v2/compliance/oval_contents/destroy.json.rabl +3 -0
  54. data/app/views/api/v2/compliance/oval_contents/index.json.rabl +3 -0
  55. data/app/views/api/v2/compliance/oval_contents/show.json.rabl +3 -0
  56. data/app/views/api/v2/compliance/oval_contents/sync.json.rabl +3 -0
  57. data/app/views/api/v2/compliance/oval_contents/sync_result.json.rabl +11 -0
  58. data/app/views/api/v2/compliance/oval_contents/update.json.rabl +3 -0
  59. data/app/views/api/v2/compliance/oval_policies/create.json.rabl +3 -0
  60. data/app/views/api/v2/compliance/oval_policies/index.json.rabl +3 -0
  61. data/app/views/api/v2/compliance/oval_policies/main.json.rabl +15 -0
  62. data/app/views/api/v2/compliance/oval_policies/show.json.rabl +3 -0
  63. data/app/views/api/v2/compliance/policies/base.json.rabl +2 -2
  64. data/app/views/api/v2/compliance/policies_common/_attrs.json.rabl +2 -0
  65. data/app/views/arf_reports/_output.html.erb +9 -1
  66. data/app/views/arf_reports/show.html.erb +1 -1
  67. data/app/views/arf_reports/show_html.html.erb +1 -0
  68. data/app/views/compliance_hosts/show.html.erb +1 -8
  69. data/app/views/job_templates/run_oval_scans.erb +24 -0
  70. data/app/views/policies/edit.html.erb +3 -2
  71. data/app/views/policies/show.html.erb +3 -1
  72. data/app/views/policies/steps/_deployment_options_form.html.erb +2 -2
  73. data/app/views/scap_contents/edit.html.erb +2 -12
  74. data/app/views/tailoring_files/edit.html.erb +2 -10
  75. data/config/initializers/inflections.rb +12 -0
  76. data/config/routes.rb +19 -0
  77. data/db/migrate/20201019074925_create_oval_policy.rb +13 -0
  78. data/db/migrate/20201020113801_create_oval_facet.rb +14 -0
  79. data/db/migrate/20201021084109_create_hostgroup_oval_facet.rb +14 -0
  80. data/db/migrate/20201106080924_create_oval_content.rb +12 -0
  81. data/db/migrate/20201116110256_add_oval_content_to_oval_policy.rb +5 -0
  82. data/db/migrate/20201120080329_create_cves.rb +13 -0
  83. data/db/migrate/20201217130800_add_has_errata_to_cve.rb +8 -0
  84. data/db/migrate/20201217161511_add_url_to_oval_content.rb +5 -0
  85. data/db/migrate/20210409095625_add_oval_policy_reference_to_cve.rb +7 -0
  86. data/db/seeds.d/75-job_templates.rb +3 -2
  87. data/lib/foreman_openscap/bulk_upload.rb +2 -2
  88. data/lib/foreman_openscap/engine.rb +67 -9
  89. data/lib/foreman_openscap/version.rb +1 -1
  90. data/lib/tasks/foreman_openscap_tasks.rake +14 -9
  91. data/locale/de/LC_MESSAGES/foreman_openscap.mo +0 -0
  92. data/locale/de/foreman_openscap.edit.po +0 -0
  93. data/locale/de/foreman_openscap.po +215 -17
  94. data/locale/en_GB/LC_MESSAGES/foreman_openscap.mo +0 -0
  95. data/locale/en_GB/foreman_openscap.edit.po +0 -0
  96. data/locale/en_GB/foreman_openscap.po +213 -15
  97. data/locale/es/LC_MESSAGES/foreman_openscap.mo +0 -0
  98. data/locale/es/foreman_openscap.edit.po +0 -0
  99. data/locale/es/foreman_openscap.po +239 -41
  100. data/locale/foreman_openscap.pot +395 -112
  101. data/locale/fr/LC_MESSAGES/foreman_openscap.mo +0 -0
  102. data/locale/fr/foreman_openscap.edit.po +0 -0
  103. data/locale/fr/foreman_openscap.po +243 -45
  104. data/locale/gl/LC_MESSAGES/foreman_openscap.mo +0 -0
  105. data/locale/gl/foreman_openscap.edit.po +0 -0
  106. data/locale/gl/foreman_openscap.po +213 -15
  107. data/locale/it/LC_MESSAGES/foreman_openscap.mo +0 -0
  108. data/locale/it/foreman_openscap.edit.po +0 -0
  109. data/locale/it/foreman_openscap.po +213 -15
  110. data/locale/ja/LC_MESSAGES/foreman_openscap.mo +0 -0
  111. data/locale/ja/foreman_openscap.edit.po +0 -0
  112. data/locale/ja/foreman_openscap.po +262 -66
  113. data/locale/ko/LC_MESSAGES/foreman_openscap.mo +0 -0
  114. data/locale/ko/foreman_openscap.edit.po +0 -0
  115. data/locale/ko/foreman_openscap.po +214 -16
  116. data/locale/pt_BR/LC_MESSAGES/foreman_openscap.mo +0 -0
  117. data/locale/pt_BR/foreman_openscap.edit.po +0 -0
  118. data/locale/pt_BR/foreman_openscap.po +252 -54
  119. data/locale/ru/LC_MESSAGES/foreman_openscap.mo +0 -0
  120. data/locale/ru/foreman_openscap.edit.po +0 -0
  121. data/locale/ru/foreman_openscap.po +214 -16
  122. data/locale/sv_SE/LC_MESSAGES/foreman_openscap.mo +0 -0
  123. data/locale/sv_SE/foreman_openscap.edit.po +0 -0
  124. data/locale/sv_SE/foreman_openscap.po +213 -15
  125. data/locale/zh_CN/LC_MESSAGES/foreman_openscap.mo +0 -0
  126. data/locale/zh_CN/foreman_openscap.edit.po +0 -0
  127. data/locale/zh_CN/foreman_openscap.po +369 -169
  128. data/locale/zh_TW/LC_MESSAGES/foreman_openscap.mo +0 -0
  129. data/locale/zh_TW/foreman_openscap.edit.po +0 -0
  130. data/locale/zh_TW/foreman_openscap.po +214 -16
  131. data/package.json +48 -0
  132. data/test/factories/compliance_host_factory.rb +12 -0
  133. data/test/factories/oval_content_factory.rb +7 -0
  134. data/test/factories/oval_policy_factory.rb +9 -0
  135. data/test/files/oval_contents/ansible-2.9.oval.xml.bz2 +0 -0
  136. data/test/fixtures/cve_fixtures.rb +104 -0
  137. data/test/functional/api/v2/compliance/oval_contents_controller_test.rb +39 -0
  138. data/test/functional/api/v2/compliance/oval_policies_controller_test.rb +141 -0
  139. data/test/functional/api/v2/compliance/oval_reports_controller_test.rb +32 -0
  140. data/test/graphql/queries/oval_contents_query_test.rb +35 -0
  141. data/test/graphql/queries/oval_policies_query_test.rb +35 -0
  142. data/test/test_plugin_helper.rb +4 -0
  143. data/test/unit/oval_host_test.rb +45 -0
  144. data/test/unit/oval_policy_test.rb +133 -0
  145. data/test/unit/oval_status_test.rb +47 -0
  146. data/test/unit/services/oval/cves_test.rb +81 -0
  147. data/test/unit/services/oval/setup_test.rb +87 -0
  148. data/webpack/components/EmptyState.js +67 -0
  149. data/webpack/components/IndexLayout.js +35 -0
  150. data/webpack/components/IndexLayout.scss +3 -0
  151. data/webpack/components/IndexTable/IndexTableHelper.js +9 -0
  152. data/webpack/components/IndexTable/index.js +65 -0
  153. data/webpack/components/RuleSeverity/RuleSeverity.scss +3 -0
  154. data/webpack/components/RuleSeverity/RuleSeverity.test.js +13 -0
  155. data/webpack/components/RuleSeverity/__snapshots__/RuleSeverity.test.js.snap +41 -0
  156. data/webpack/components/RuleSeverity/i_severity-critical.svg +61 -0
  157. data/webpack/components/RuleSeverity/i_severity-high.svg +61 -0
  158. data/webpack/components/RuleSeverity/i_severity-low.svg +62 -0
  159. data/webpack/components/RuleSeverity/i_severity-med.svg +62 -0
  160. data/webpack/components/RuleSeverity/i_unknown.svg +33 -0
  161. data/webpack/components/RuleSeverity/index.js +33 -0
  162. data/webpack/components/withLoading.js +68 -0
  163. data/webpack/global_index.js +5 -0
  164. data/webpack/graphql/queries/cves.gql +18 -0
  165. data/webpack/graphql/queries/ovalContents.gql +11 -0
  166. data/webpack/graphql/queries/ovalPolicies.gql +12 -0
  167. data/webpack/graphql/queries/ovalPolicy.gql +21 -0
  168. data/webpack/helpers/commonHelper.js +1 -0
  169. data/webpack/helpers/globalIdHelper.js +13 -0
  170. data/webpack/helpers/pageParamsHelper.js +31 -0
  171. data/webpack/helpers/pathsHelper.js +22 -0
  172. data/webpack/helpers/tableHelper.js +9 -0
  173. data/webpack/index.js +8 -0
  174. data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsIndex.js +45 -0
  175. data/webpack/routes/OvalContents/OvalContentsIndex/OvalContentsTable.js +38 -0
  176. data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.fixtures.js +106 -0
  177. data/webpack/routes/OvalContents/OvalContentsIndex/__tests__/OvalContentsIndex.test.js +75 -0
  178. data/webpack/routes/OvalContents/OvalContentsIndex/index.js +7 -0
  179. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesIndex.js +46 -0
  180. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/OvalPoliciesTable.js +44 -0
  181. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.fixtures.js +61 -0
  182. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/__tests__/OvalPoliciesIndex.test.js +78 -0
  183. data/webpack/routes/OvalPolicies/OvalPoliciesIndex/index.js +7 -0
  184. data/webpack/routes/OvalPolicies/OvalPoliciesShow/CvesTab.js +48 -0
  185. data/webpack/routes/OvalPolicies/OvalPoliciesShow/CvesTable.js +63 -0
  186. data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShow.js +78 -0
  187. data/webpack/routes/OvalPolicies/OvalPoliciesShow/OvalPoliciesShowHelper.js +39 -0
  188. data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.fixtures.js +78 -0
  189. data/webpack/routes/OvalPolicies/OvalPoliciesShow/__tests__/OvalPoliciesShow.test.js +112 -0
  190. data/webpack/routes/OvalPolicies/OvalPoliciesShow/index.js +35 -0
  191. data/webpack/routes/routes.js +28 -0
  192. data/webpack/testHelper.js +64 -0
  193. metadata +144 -3
@@ -0,0 +1,33 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
+ viewBox="0 0 110 130" style="enable-background:new 0 0 110 130;" xml:space="preserve">
5
+ <style type="text/css">
6
+ .st0{fill:#CCCCCC;}
7
+ .st1{fill:#FFFFFF;}
8
+ </style>
9
+ <path class="st0" d="M96.6,130H13c-7.2,0-13-5.9-13-13l0,0c0-7.2,5.9-13,13-13h83.6c7.2,0,13,5.9,13,13l0,0
10
+ C109.7,124.1,103.8,130,96.6,130z M96.6,95.4H13c-7.2,0-13-5.9-13-13l0,0c0-7.2,5.9-13,13-13h83.6c7.2,0,13,5.9,13,13l0,0
11
+ C109.7,89.5,103.8,95.4,96.6,95.4z M97,60.2H13.4c-7.2,0-13-5.9-13-13l0,0c0-7.2,5.9-13,13-13H97c7.2,0,13,5.9,13,13l0,0
12
+ C110,54.4,104.1,60.2,97,60.2z M96.6,26.1H13c-7.2,0-13-5.9-13-13l0,0C0,5.9,5.9,0,13,0h83.6c7.2,0,13,5.9,13,13l0,0
13
+ C109.7,20.2,103.8,26.1,96.6,26.1z"/>
14
+ <path class="st0" d="M53.3,123.4c-4.6,0-8.5-1.6-11.6-4.6c-3.2-3.1-4.8-7-4.8-11.5s1.6-8.4,4.8-11.5c1-1,2.1-1.8,3.3-2.5h-4.9v-8.7
15
+ c0-4.9,0.7-9.3,2.1-13.3c1.4-4,3.3-7.3,5.5-9.8c1.9-2.1,4.1-4.3,6.3-6.3c2.2-2,4.3-3.8,6.2-5.3c1.4-1.1,2.5-2.5,3.5-4.2
16
+ c0.9-1.6,1.3-3.2,1.3-5c0-2.7-0.8-4.7-2.5-6.3c-1.7-1.7-4.2-2.5-7.6-2.5c-4.2,0-7.3,1.2-9.4,3.5c-2.3,2.5-3.4,6.1-3.4,10.9V51H15.6
17
+ v-4.5c0-12.2,3.7-22,10.9-29.2c7.2-7.1,16.7-10.8,28.4-10.8c11.3,0,20.3,3.2,26.8,9.6c6.5,6.4,9.8,14.7,9.8,24.7
18
+ c0,4.4-0.7,8.5-2.2,12.1c-1.5,3.6-3.4,6.6-5.6,8.9c-1.9,1.9-3.9,3.8-6.1,5.9c-2.1,2-4.1,3.8-6,5.5c-1.4,1.2-2.6,2.9-3.6,4.9
19
+ c-1,2-1.4,4.2-1.4,6.7v8.5h-4.8c1.2,0.7,2.3,1.6,3.4,2.6c3.2,3.2,4.7,7,4.7,11.4c0,4.5-1.6,8.4-4.8,11.5
20
+ C61.8,121.9,57.9,123.4,53.3,123.4z"/>
21
+ <path class="st1" d="M54.8,11.1c10.1,0,18,2.8,23.6,8.3c5.6,5.6,8.4,12.7,8.4,21.5c0,3.9-0.6,7.4-1.9,10.4c-1.2,3.1-2.8,5.5-4.6,7.4
22
+ c-1.8,1.8-3.8,3.8-6,5.7c-2.1,2-4.1,3.8-6,5.4c-1.8,1.6-3.4,3.8-4.6,6.3c-1.2,2.6-1.9,5.5-1.9,8.6v4H44.6v-4.2
23
+ c0-4.4,0.6-8.3,1.9-11.8c1.2-3.5,2.8-6.2,4.6-8.3c1.8-2,3.8-4,6-6c2.1-1.9,4.1-3.6,6-5.1c1.8-1.4,3.4-3.3,4.6-5.5
24
+ c1.2-2.2,1.9-4.6,1.9-7.2c0-3.9-1.3-7.1-3.9-9.5c-2.6-2.5-6.2-3.7-10.7-3.7c-5.5,0-9.7,1.7-12.7,5c-3,3.3-4.5,8-4.5,13.9H20.1
25
+ c0-11,3.2-19.7,9.5-26C36,14.2,44.4,11.1,54.8,11.1 M53.3,95.7c3.4,0,6.2,1.1,8.5,3.4c2.3,2.3,3.4,5,3.4,8.2c0,3.3-1.1,6-3.4,8.3
26
+ c-2.3,2.2-5.1,3.4-8.5,3.4c-3.4,0-6.2-1.1-8.5-3.4c-2.3-2.2-3.4-5-3.4-8.3c0-3.3,1.1-6,3.4-8.3C47.1,96.8,50,95.7,53.3,95.7
27
+ M54.8,2.1C42,2.1,31.4,6.1,23.3,14.1c-8.1,8-12.2,18.9-12.2,32.4v9h9h17.4h9v-9c0-3.6,0.7-6.3,2.2-7.9c0.8-0.9,2.3-2.1,6.1-2.1
28
+ c2.1,0,3.7,0.4,4.5,1.2c0.5,0.5,1.1,1.2,1.1,3c0,1.1-0.2,2-0.7,2.9c-0.7,1.2-1.4,2.1-2.3,2.8c-2,1.6-4.2,3.4-6.5,5.5
29
+ c-2.3,2.1-4.6,4.3-6.6,6.6c-2.6,2.9-4.8,6.7-6.4,11.3c-1.6,4.4-2.4,9.4-2.4,14.8v4.2v7.5c-2.1,3.2-3.1,7-3.1,11
30
+ c0,5.7,2.1,10.8,6.1,14.7c4,3.9,9.1,5.9,14.8,5.9c5.7,0,10.8-2,14.8-5.9c4-3.9,6.1-9,6.1-14.7c0-4.1-1.1-7.9-3.3-11.1v-7.3v-4
31
+ c0-1.8,0.3-3.4,1-4.7c0.7-1.5,1.6-2.7,2.5-3.5c1.9-1.7,4-3.6,6.1-5.6c2.2-2,4.3-4,6.2-6c2.7-2.7,4.9-6.2,6.6-10.4
32
+ c1.7-4.1,2.5-8.8,2.5-13.8c0-11.2-3.7-20.6-11.1-27.8C77.5,5.7,67.4,2.1,54.8,2.1L54.8,2.1z"/>
33
+ </svg>
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import SeverityCritical from './i_severity-critical.svg';
5
+ import SeverityHigh from './i_severity-high.svg';
6
+ import SeverityMedium from './i_severity-med.svg';
7
+ import SeverityLow from './i_severity-low.svg';
8
+ import SeverityUnknown from './i_unknown.svg';
9
+
10
+ import './RuleSeverity.scss';
11
+
12
+ const RuleSeverity = props => {
13
+ const propsMapping = {
14
+ low: { alt: 'Low Serverity', src: SeverityLow },
15
+ medium: { alt: 'Medium Serverity', src: SeverityMedium },
16
+ high: { alt: 'High Serverity', src: SeverityHigh },
17
+ critical: {
18
+ alt: 'Critical Serverity',
19
+ src: SeverityCritical,
20
+ },
21
+ unknown: { alt: 'Unknown Serverity', src: SeverityUnknown },
22
+ };
23
+
24
+ const imgProps = propsMapping[props.severity] || propsMapping.unknown;
25
+ // eslint-disable-next-line jsx-a11y/alt-text
26
+ return <img {...imgProps} className="severity-img" />;
27
+ };
28
+
29
+ RuleSeverity.propTypes = {
30
+ severity: PropTypes.string.isRequired,
31
+ };
32
+
33
+ export default RuleSeverity;
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+
5
+ import Loading from 'foremanReact/components/Loading';
6
+ import EmptyState from './EmptyState';
7
+
8
+ const errorStateTitle = __('Error!');
9
+ const emptyStateBody = '';
10
+
11
+ const pluckData = (data, path) => {
12
+ const split = path.split('.');
13
+ return split.reduce((memo, item) => {
14
+ if (item) {
15
+ return memo[item];
16
+ }
17
+ throw new Error('Unexpected empty segment in response data path');
18
+ }, data);
19
+ };
20
+
21
+ const withLoading = Component => {
22
+ const Subcomponent = ({
23
+ fetchFn,
24
+ resultPath,
25
+ renameData,
26
+ emptyStateTitle,
27
+ ...rest
28
+ }) => {
29
+ const { loading, error, data } = fetchFn(rest);
30
+
31
+ if (loading) {
32
+ return <Loading />;
33
+ }
34
+
35
+ if (error) {
36
+ return (
37
+ <EmptyState
38
+ error={error}
39
+ title={errorStateTitle}
40
+ body={error.message}
41
+ />
42
+ );
43
+ }
44
+
45
+ const result = pluckData(data, resultPath);
46
+
47
+ if ((Array.isArray(result) && result.length === 0) || !result) {
48
+ return <EmptyState title={emptyStateTitle} body={emptyStateBody} />;
49
+ }
50
+
51
+ return <Component {...rest} {...renameData(data)} />;
52
+ };
53
+
54
+ Subcomponent.propTypes = {
55
+ fetchFn: PropTypes.func.isRequired,
56
+ resultPath: PropTypes.string.isRequired,
57
+ renameData: PropTypes.func,
58
+ emptyStateTitle: PropTypes.string.isRequired,
59
+ };
60
+
61
+ Subcomponent.defaultProps = {
62
+ renameData: data => data,
63
+ };
64
+
65
+ return Subcomponent;
66
+ };
67
+
68
+ export default withLoading;
@@ -0,0 +1,5 @@
1
+ import { registerRoutes } from 'foremanReact/routes/RoutingService';
2
+
3
+ import routes from './routes/routes';
4
+
5
+ registerRoutes('foreman_openscap', routes);
@@ -0,0 +1,18 @@
1
+ query($search: String, $first: Int, $last: Int) {
2
+ cves(search: $search, first: $first, last: $last) {
3
+ totalCount
4
+ nodes {
5
+ id
6
+ refId
7
+ refUrl
8
+ hasErrata
9
+ definitionId
10
+ hosts {
11
+ nodes {
12
+ id
13
+ name
14
+ }
15
+ }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ query($first: Int, $last: Int) {
2
+ ovalContents(first: $first, last: $last) {
3
+ totalCount
4
+ nodes {
5
+ id
6
+ name
7
+ url
8
+ originalFilename
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ query($first: Int, $last: Int) {
2
+ ovalPolicies(first: $first, last: $last) {
3
+ totalCount
4
+ nodes {
5
+ id
6
+ name
7
+ ovalContent {
8
+ name
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,21 @@
1
+ query($id: String!) {
2
+ ovalPolicy(id: $id) {
3
+ id
4
+ name
5
+ period
6
+ cronLine
7
+ weekday
8
+ dayOfMonth
9
+ description
10
+ hostgroups {
11
+ nodes {
12
+ id
13
+ descendants {
14
+ nodes {
15
+ id
16
+ }
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export const last = array => array[array.length - 1];
@@ -0,0 +1,13 @@
1
+ import { last } from './commonHelper';
2
+
3
+ const idSeparator = '-';
4
+ const versionSeparator = ':';
5
+ const defaultVersion = '01';
6
+
7
+ export const decodeId = model => {
8
+ const split = atob(model.id).split(idSeparator);
9
+ return parseInt(last(split), 10);
10
+ };
11
+
12
+ export const encodeId = (typename, id) =>
13
+ btoa([defaultVersion, versionSeparator, typename, idSeparator, id].join(''));
@@ -0,0 +1,31 @@
1
+ import URI from 'urijs';
2
+ import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
3
+
4
+ const parsePageParams = history => URI.parseQuery(history.location.search);
5
+
6
+ export const addSearch = (basePath, params) => {
7
+ let stringyfied = '';
8
+ if (Object.keys(params).length > 0) {
9
+ stringyfied = `?${URI.buildQuery(params)}`;
10
+ }
11
+
12
+ return `${basePath}${stringyfied}`;
13
+ };
14
+
15
+ export const useCurrentPagination = history => {
16
+ const pageParams = parsePageParams(history);
17
+ const uiSettings = useForemanSettings();
18
+
19
+ return {
20
+ page: parseInt(pageParams.page, 10) || 1,
21
+ perPage: parseInt(pageParams.perPage, 10) || uiSettings.perPage,
22
+ };
23
+ };
24
+
25
+ export const pageToVars = pagination => ({
26
+ first: pagination.page * pagination.perPage,
27
+ last: pagination.perPage,
28
+ });
29
+
30
+ export const useParamsToVars = history =>
31
+ pageToVars(useCurrentPagination(history));
@@ -0,0 +1,22 @@
1
+ import { decodeId } from './globalIdHelper';
2
+
3
+ const experimental = path => `/experimental${path}`;
4
+
5
+ const showPath = path => `${path}/:id`;
6
+
7
+ export const modelPath = (basePath, model) => `${basePath}/${decodeId(model)}`;
8
+
9
+ // react-router uses path-to-regexp, should we use it as well in a future?
10
+ // https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#compile-reverse-path-to-regexp
11
+ export const resolvePath = (path, params) =>
12
+ Object.entries(params).reduce(
13
+ (memo, [key, value]) => memo.replace(key, value),
14
+ path
15
+ );
16
+
17
+ export const ovalContentsPath = experimental('/compliance/oval_contents');
18
+ export const ovalPoliciesPath = experimental('/compliance/oval_policies');
19
+ export const ovalPoliciesShowPath = `${showPath(ovalPoliciesPath)}/:tab?`;
20
+ export const hostsPath = '/hosts';
21
+ export const newJobPath = '/job_invocations/new';
22
+ export const hostsShowPath = showPath(hostsPath);
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { Link } from 'react-router-dom';
3
+ import { TableText } from '@patternfly/react-table';
4
+
5
+ export const linkCell = (path, text) => (
6
+ <TableText>
7
+ <Link to={path}>{text}</Link>
8
+ </TableText>
9
+ );
data/webpack/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import componentRegistry from 'foremanReact/components/componentRegistry';
2
+
3
+ import RuleSeverity from './components/RuleSeverity';
4
+
5
+ componentRegistry.register({
6
+ name: 'RuleSeverity',
7
+ type: RuleSeverity,
8
+ });
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useQuery } from '@apollo/client';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+
6
+ import IndexLayout from '../../../components/IndexLayout';
7
+ import OvalContentsTable from './OvalContentsTable';
8
+ import {
9
+ useParamsToVars,
10
+ useCurrentPagination,
11
+ } from '../../../helpers/pageParamsHelper';
12
+ import ovalContentsQuery from '../../../graphql/queries/ovalContents.gql';
13
+
14
+ const OvalContentsIndex = props => {
15
+ const useFetchFn = componentProps =>
16
+ useQuery(ovalContentsQuery, {
17
+ variables: useParamsToVars(componentProps.history),
18
+ });
19
+
20
+ const renameData = data => ({
21
+ ovalContents: data.ovalContents.nodes,
22
+ totalCount: data.ovalContents.totalCount,
23
+ });
24
+
25
+ const pagination = useCurrentPagination(props.history);
26
+
27
+ return (
28
+ <IndexLayout pageTitle={__('OVAL Contents')}>
29
+ <OvalContentsTable
30
+ {...props}
31
+ fetchFn={useFetchFn}
32
+ renameData={renameData}
33
+ resultPath="ovalContents.nodes"
34
+ pagination={pagination}
35
+ emptyStateTitle={__('No OVAL Contents found.')}
36
+ />
37
+ </IndexLayout>
38
+ );
39
+ };
40
+
41
+ OvalContentsIndex.propTypes = {
42
+ history: PropTypes.object.isRequired,
43
+ };
44
+
45
+ export default OvalContentsIndex;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+
5
+ import withLoading from '../../../components/withLoading';
6
+ import IndexTable from '../../../components/IndexTable';
7
+
8
+ const OvalContentsTable = props => {
9
+ const columns = [{ title: __('Name') }];
10
+
11
+ const rows = props.ovalContents.map(ovalContent => ({
12
+ cells: [{ title: ovalContent.name }],
13
+ ovalContent,
14
+ }));
15
+
16
+ const actions = [];
17
+
18
+ return (
19
+ <IndexTable
20
+ columns={columns}
21
+ rows={rows}
22
+ actions={actions}
23
+ pagination={props.pagination}
24
+ totalCount={props.totalCount}
25
+ history={props.history}
26
+ ariaTableLabel={__('OVAL Contents table')}
27
+ />
28
+ );
29
+ };
30
+
31
+ OvalContentsTable.propTypes = {
32
+ ovalContents: PropTypes.array.isRequired,
33
+ pagination: PropTypes.object.isRequired,
34
+ totalCount: PropTypes.number.isRequired,
35
+ history: PropTypes.object.isRequired,
36
+ };
37
+
38
+ export default withLoading(OvalContentsTable);
@@ -0,0 +1,106 @@
1
+ import ovalContentsQuery from '../../../../graphql/queries/ovalContents.gql';
2
+ import { ovalContentsPath } from '../../../../helpers/pathsHelper';
3
+ import { mockFactory } from '../../../../testHelper';
4
+
5
+ const ovalContentMockFactory = mockFactory('ovalContents', ovalContentsQuery);
6
+
7
+ export const mocks = [
8
+ {
9
+ request: {
10
+ query: ovalContentsQuery,
11
+ variables: {
12
+ first: 20,
13
+ last: 20,
14
+ },
15
+ },
16
+ result: {
17
+ data: {
18
+ ovalContents: {
19
+ totalCount: 4,
20
+ nodes: [
21
+ {
22
+ id: 'abc',
23
+ name: 'ansible OVAL content',
24
+ url:
25
+ 'http://oval-content-source/security/data/oval/ansible-2-including-unpatched.oval.xml.bz2',
26
+ originalFilename: '',
27
+ },
28
+ {
29
+ id: 'bcd',
30
+ name: 'dotnet OVAL content',
31
+ url:
32
+ 'http://oval-content-source/security/data/oval/dotnet-2.2.oval.xml.bz2',
33
+ originalFilename: '',
34
+ },
35
+ {
36
+ id: 'cde',
37
+ name: 'jboss OVAL content',
38
+ url: '',
39
+ originalFilename: 'jboss.oval.xml.bz2',
40
+ },
41
+ {
42
+ id: 'def',
43
+ name: 'openshift OVAL content',
44
+ url: '',
45
+ originalFilename: 'openshift.oval.xml.bz2',
46
+ },
47
+ ],
48
+ },
49
+ },
50
+ },
51
+ },
52
+ ];
53
+
54
+ export const paginatedMocks = [
55
+ {
56
+ request: {
57
+ query: ovalContentsQuery,
58
+ variables: {
59
+ first: 10,
60
+ last: 5,
61
+ },
62
+ },
63
+ result: {
64
+ data: {
65
+ ovalContents: {
66
+ totalCount: 7,
67
+ nodes: [
68
+ {
69
+ id: 'bcd',
70
+ name: 'dotnet OVAL content',
71
+ url:
72
+ 'http://oval-content-source/security/data/oval/dotnet-2.2.oval.xml.bz2',
73
+ originalFilename: '',
74
+ },
75
+ {
76
+ id: 'def',
77
+ name: 'openshift OVAL content',
78
+ url: '',
79
+ originalFilename: 'openshift.oval.xml.bz2',
80
+ },
81
+ ],
82
+ },
83
+ },
84
+ },
85
+ },
86
+ ];
87
+
88
+ export const emptyMocks = ovalContentMockFactory(
89
+ { first: 20, last: 20 },
90
+ { totalCount: 0, nodes: [] }
91
+ );
92
+ export const errorMocks = ovalContentMockFactory(
93
+ { first: 20, last: 20 },
94
+ { totalCount: 0, nodes: [] },
95
+ [{ message: 'Something very bad happened.' }]
96
+ );
97
+
98
+ export const pushMock = jest.fn();
99
+
100
+ export const pagePaginationHistoryMock = {
101
+ location: {
102
+ search: '?page=2&perPage=5',
103
+ pathname: ovalContentsPath,
104
+ },
105
+ push: pushMock,
106
+ };