@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.3
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.
- package/apis/impl/apis.ts +6 -0
- package/apis/index.ts +26 -0
- package/apis/intf/resources-api/cluster-api.ts +18 -0
- package/apis/intf/resources-api/mgmt-api.ts +15 -0
- package/apis/intf/resources-api/resource-base.ts +107 -0
- package/apis/intf/resources-api/resource-constants.ts +147 -0
- package/apis/intf/resources-api/resources-api.ts +143 -0
- package/apis/intf/resources.ts +49 -0
- package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
- package/apis/intf/shell-api/proxy.ts +216 -0
- package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
- package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
- package/apis/intf/shell.ts +12 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
- package/apis/resources/index.ts +22 -0
- package/apis/resources/resources-api-class.ts +187 -0
- package/apis/shell/__tests__/proxy.test.ts +369 -0
- package/apis/shell/index.ts +8 -1
- package/apis/shell/modal.ts +4 -1
- package/apis/shell/notifications.ts +9 -6
- package/apis/shell/proxy.ts +256 -0
- package/apis/shell/slide-in.ts +4 -1
- package/apis/vue-shim.d.ts +2 -1
- package/assets/data/aws-regions.json +4 -0
- package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
- package/assets/images/providers/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/translations/en-us.yaml +41 -22
- package/assets/translations/zh-hans.yaml +4 -8
- package/chart/__tests__/S3.test.ts +10 -3
- package/chart/monitoring/index.vue +10 -1
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/CruResourceFooter.vue +9 -5
- package/components/DetailText.vue +12 -3
- package/components/ExplorerProjectsNamespaces.vue +1 -1
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
- package/components/Resource/Detail/Metadata/index.vue +6 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
- package/components/Resource/Detail/SpacedRow.vue +3 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -11
- package/components/ResourceList/Masthead.vue +12 -8
- package/components/SelectIconGrid.vue +5 -10
- package/components/SingleClusterInfo.vue +1 -0
- package/components/SortableTable/__tests__/sorting.test.ts +126 -0
- package/components/SortableTable/index.vue +6 -9
- package/components/SortableTable/selection.js +23 -5
- package/components/SortableTable/sorting.js +6 -3
- package/components/Wizard.vue +14 -13
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/index.vue +54 -15
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +101 -26
- package/components/form/NameNsDescription.vue +11 -0
- package/components/form/Security.vue +6 -2
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/__tests__/Security.test.ts +76 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/formatter/Autoscaler.vue +4 -4
- package/components/formatter/ClusterKubeVersion.vue +27 -0
- package/components/formatter/ClusterLink.vue +1 -7
- package/components/formatter/ClusterProvider.vue +6 -10
- package/components/formatter/FleetSummaryGraph.vue +0 -3
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/nav/Group.vue +7 -6
- package/components/nav/Header.vue +24 -3
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +16 -5
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +30 -25
- package/components/templates/plain.vue +31 -26
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/manager.js +82 -21
- package/config/query-params.js +1 -0
- package/config/router/routes.js +6 -8
- package/config/table-headers.js +20 -1
- package/config/types.js +2 -1
- package/core/__tests__/plugin-products.test.ts +1505 -30
- package/core/plugin-products-base.ts +137 -20
- package/core/plugin-products-helpers.ts +5 -4
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +129 -4
- package/core/plugin.ts +15 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +43 -30
- package/core/types.ts +58 -19
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -10
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/azuread.test.ts +217 -34
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +123 -15
- package/edit/auth/oidc.vue +10 -2
- package/edit/kontainerDriver.vue +1 -2
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
- package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
- package/edit/networking.k8s.io.ingress/index.vue +75 -20
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
- package/edit/secret/__tests__/ssh.test.ts +5 -6
- package/edit/secret/basic.vue +31 -0
- package/edit/secret/index.vue +68 -17
- package/edit/secret/registry.vue +38 -0
- package/edit/secret/ssh.vue +29 -0
- package/edit/secret/tls.vue +30 -0
- package/edit/service.vue +4 -4
- package/edit/workload/Upgrading.vue +3 -3
- package/edit/workload/__tests__/Upgrading.test.ts +6 -9
- package/edit/workload/mixins/workload.js +2 -1
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/list/provisioning.cattle.io.cluster.vue +262 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/__tests__/chart.test.ts +112 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +50 -15
- package/mixins/resource-fetch-api-pagination.js +41 -5
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/management.cattle.io.node.ts +6 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/cluster.js +1 -1
- package/models/cluster.x-k8s.io.machine.js +4 -22
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
- package/models/cluster.x-k8s.io.machineset.js +2 -20
- package/models/compliance.cattle.io.clusterscan.js +130 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +4 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +402 -78
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/nodedriver.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +47 -330
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/package.json +20 -37
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/auth/setup.vue +2 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +275 -39
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +18 -10
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
- package/pages/c/_cluster/istio/index.vue +21 -6
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
- package/pages/c/_cluster/uiplugins/index.vue +226 -222
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +18 -0
- package/pages/home.vue +77 -260
- package/pages/readme.vue +88 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +5 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/steve-pagination-utils.ts +11 -3
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/rancher-components/RcButton/RcButton.test.ts +37 -1
- package/rancher-components/RcButton/RcButton.vue +38 -8
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/scripts/test-plugins-build.sh +5 -2
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +276 -12
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -4
- package/store/aws.js +27 -16
- package/store/catalog.js +87 -11
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/kube/kube-api.ts +14 -1
- package/types/rancher/steve.api.ts +12 -12
- package/types/resources/settings.d.ts +2 -1
- package/types/shell/index.d.ts +128 -24
- package/types/store/dashboard-store.types.ts +108 -11
- package/types/store/pagination.types.ts +6 -3
- package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
- package/utils/__tests__/async.test.ts +87 -0
- package/utils/__tests__/aws.test.ts +140 -0
- package/utils/__tests__/banners.test.ts +176 -0
- package/utils/__tests__/chart.test.ts +64 -1
- package/utils/__tests__/color.test.ts +226 -0
- package/utils/__tests__/duration.test.ts +140 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/pagination-utils.test.ts +361 -0
- package/utils/__tests__/parse-externalid.test.ts +137 -0
- package/utils/__tests__/perf-setting.utils.test.ts +98 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/settings.test.ts +140 -0
- package/utils/__tests__/sort-utils.test.ts +301 -0
- package/utils/__tests__/string-utils.test.ts +798 -0
- package/utils/__tests__/string.test.ts +23 -1
- package/utils/__tests__/style.test.ts +154 -0
- package/utils/__tests__/svg-filter.test.ts +184 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/xccdf.test.ts +391 -0
- package/utils/chart.js +36 -0
- package/utils/fleet.ts +13 -3
- package/utils/gatekeeper/__tests__/util.test.ts +174 -0
- package/utils/gc/__tests__/gc-interval.test.ts +119 -0
- package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
- package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
- package/utils/gc/__tests__/gc.test.ts +487 -0
- package/utils/ingress.ts +9 -1
- package/utils/object.js +33 -2
- package/utils/pagination-utils.ts +2 -1
- package/utils/string.js +25 -2
- package/utils/time.ts +5 -0
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
- package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
- package/utils/validators/__tests__/role-template.test.ts +149 -0
- package/utils/validators/__tests__/service.test.ts +283 -0
- package/utils/validators/__tests__/setting.test.js +32 -0
- package/utils/validators/formRules/__tests__/index.test.ts +50 -0
- package/utils/validators/formRules/index.ts +5 -5
- package/utils/validators/machine-pool.ts +1 -1
- package/utils/validators/setting.js +18 -3
- package/utils/xccdf.ts +418 -0
- package/vue.config.js +0 -9
- package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
function makeStoreWithCalls(rancherPromise: Promise<any>, kubePromise: Promise<any>) {
|
|
2
|
+
let callCount = 0;
|
|
3
|
+
|
|
4
|
+
return {
|
|
5
|
+
dispatch: jest.fn(() => {
|
|
6
|
+
callCount++;
|
|
7
|
+
|
|
8
|
+
return callCount === 1 ? rancherPromise : kubePromise;
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('versions', () => {
|
|
14
|
+
let versions: any;
|
|
15
|
+
let mockSetVersionData: jest.Mock;
|
|
16
|
+
let mockSetKubeVersionData: jest.Mock;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
mockSetVersionData = jest.fn();
|
|
21
|
+
mockSetKubeVersionData = jest.fn();
|
|
22
|
+
jest.mock('@shell/config/version', () => ({
|
|
23
|
+
setVersionData: mockSetVersionData,
|
|
24
|
+
setKubeVersionData: mockSetKubeVersionData,
|
|
25
|
+
}));
|
|
26
|
+
versions = require('@shell/utils/versions').default;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('fetch', () => {
|
|
30
|
+
it('dispatches rancher/request for /rancherversion', async() => {
|
|
31
|
+
const store = { dispatch: jest.fn(() => Promise.resolve({})) };
|
|
32
|
+
|
|
33
|
+
await versions.fetch({ store });
|
|
34
|
+
|
|
35
|
+
expect(store.dispatch).toHaveBeenCalledWith('rancher/request', {
|
|
36
|
+
url: '/rancherversion',
|
|
37
|
+
method: 'get',
|
|
38
|
+
redirectUnauthorized: false,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('dispatches rancher/request for /version', async() => {
|
|
43
|
+
const store = { dispatch: jest.fn(() => Promise.resolve({})) };
|
|
44
|
+
|
|
45
|
+
await versions.fetch({ store });
|
|
46
|
+
|
|
47
|
+
expect(store.dispatch).toHaveBeenCalledWith('rancher/request', {
|
|
48
|
+
url: '/version',
|
|
49
|
+
method: 'get',
|
|
50
|
+
redirectUnauthorized: false,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('calls setVersionData with the rancher version response', async() => {
|
|
55
|
+
const rancherResponse = { Version: '2.9.0', GitCommit: 'abc123' };
|
|
56
|
+
const store = makeStoreWithCalls(Promise.resolve(rancherResponse), Promise.resolve({}));
|
|
57
|
+
|
|
58
|
+
await versions.fetch({ store });
|
|
59
|
+
|
|
60
|
+
expect(mockSetVersionData).toHaveBeenCalledWith(rancherResponse);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('calls setKubeVersionData with the kube version response', async() => {
|
|
64
|
+
const kubeResponse = { gitVersion: 'v1.29.0' };
|
|
65
|
+
const store = makeStoreWithCalls(Promise.resolve({}), Promise.resolve(kubeResponse));
|
|
66
|
+
|
|
67
|
+
await versions.fetch({ store });
|
|
68
|
+
|
|
69
|
+
expect(mockSetKubeVersionData).toHaveBeenCalledWith(kubeResponse);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('caches the promise — second call does not dispatch again', async() => {
|
|
73
|
+
const store = { dispatch: jest.fn(() => Promise.resolve({})) };
|
|
74
|
+
|
|
75
|
+
await versions.fetch({ store });
|
|
76
|
+
await versions.fetch({ store });
|
|
77
|
+
|
|
78
|
+
expect(store.dispatch).toHaveBeenCalledTimes(2);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('returns the same promise object on repeated calls', () => {
|
|
82
|
+
const store = { dispatch: jest.fn(() => Promise.resolve({})) };
|
|
83
|
+
|
|
84
|
+
versions.fetch({ store });
|
|
85
|
+
versions.fetch({ store });
|
|
86
|
+
|
|
87
|
+
// Both initial calls should dispatch only twice total (2 endpoints, cached after that)
|
|
88
|
+
expect(store.dispatch).toHaveBeenCalledTimes(2);
|
|
89
|
+
// Third fetch should not dispatch additional times
|
|
90
|
+
versions.fetch({ store });
|
|
91
|
+
expect(store.dispatch).toHaveBeenCalledTimes(2);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('does not throw when rancher request fails', async() => {
|
|
95
|
+
const store = makeStoreWithCalls(Promise.reject(new Error('network error')), Promise.resolve({}));
|
|
96
|
+
|
|
97
|
+
await expect(versions.fetch({ store })).resolves.not.toThrow();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('does not throw when kube request fails', async() => {
|
|
101
|
+
const store = makeStoreWithCalls(Promise.resolve({}), Promise.reject(new Error('network error')));
|
|
102
|
+
|
|
103
|
+
await expect(versions.fetch({ store })).resolves.not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('logs a warning when rancher request fails', async() => {
|
|
107
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
108
|
+
const error = new Error('rancher down');
|
|
109
|
+
const store = makeStoreWithCalls(Promise.reject(error), Promise.resolve({}));
|
|
110
|
+
|
|
111
|
+
await versions.fetch({ store });
|
|
112
|
+
|
|
113
|
+
expect(warnSpy).toHaveBeenCalledWith('Failed to fetch Rancher version metadata', error);
|
|
114
|
+
warnSpy.mockRestore();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('logs a warning when kube request fails', async() => {
|
|
118
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
119
|
+
const error = new Error('kube down');
|
|
120
|
+
const store = makeStoreWithCalls(Promise.resolve({}), Promise.reject(error));
|
|
121
|
+
|
|
122
|
+
await versions.fetch({ store });
|
|
123
|
+
|
|
124
|
+
expect(warnSpy).toHaveBeenCalledWith('Failed to fetch Kube version metadata', error);
|
|
125
|
+
warnSpy.mockRestore();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { generateXCCDF, generateXCCDFPerNode } from '@shell/utils/xccdf';
|
|
2
|
+
|
|
3
|
+
describe('xccdf util: generateXCCDF', () => {
|
|
4
|
+
const baseReport = {
|
|
5
|
+
version: '1.0',
|
|
6
|
+
total: 2,
|
|
7
|
+
pass: 1,
|
|
8
|
+
nodes: { master: ['node-a'], node: ['node-b'] },
|
|
9
|
+
results: [{
|
|
10
|
+
id: '5.1',
|
|
11
|
+
description: 'RBAC and Service Accounts',
|
|
12
|
+
checks: [{
|
|
13
|
+
id: '5.1.1',
|
|
14
|
+
description: 'Ensure that the cluster-admin role is only used where required',
|
|
15
|
+
audit: 'kubectl get clusterrolebindings',
|
|
16
|
+
remediation: 'Identify all clusterrolebindings to the cluster-admin role',
|
|
17
|
+
scored: true,
|
|
18
|
+
state: 'pass',
|
|
19
|
+
}, {
|
|
20
|
+
id: '5.1.2',
|
|
21
|
+
description: 'Minimize access to secrets',
|
|
22
|
+
audit: 'kubectl get roles',
|
|
23
|
+
remediation: 'Where possible, remove get, list and watch access to Secret objects',
|
|
24
|
+
scored: false,
|
|
25
|
+
state: 'fail',
|
|
26
|
+
}],
|
|
27
|
+
}],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
it('produces an XML document with an XML header and a Benchmark root', () => {
|
|
31
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
32
|
+
|
|
33
|
+
expect(xml).toMatch(/^<\?xml version="1\.0" encoding="UTF-8"\?>/);
|
|
34
|
+
expect(xml).toContain('<Benchmark');
|
|
35
|
+
expect(xml).toContain('xmlns="http://checklists.nist.gov/xccdf/1.2"');
|
|
36
|
+
expect(xml).toContain('id="xccdf_compliance-operator_benchmark_kubernetes"');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('uses the metadata title when provided, otherwise falls back to a CIS title from benchmarkVersion', () => {
|
|
40
|
+
const fallback = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
41
|
+
|
|
42
|
+
expect(fallback).toContain('<title>Kubernetes CIS Benchmark cis-1.7</title>');
|
|
43
|
+
|
|
44
|
+
const withTitle = generateXCCDF({
|
|
45
|
+
report: baseReport,
|
|
46
|
+
benchmarkVersion: 'cis-1.7',
|
|
47
|
+
metadata: { title: 'Custom Benchmark Title' },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(withTitle).toContain('<title>Custom Benchmark Title</title>');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('emits one Group per result and one Rule per check', () => {
|
|
54
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
55
|
+
|
|
56
|
+
expect(xml).toContain('<Group id="5.1">');
|
|
57
|
+
expect(xml).toContain('id="xccdf_compliance-operator_rule_5.1.1"');
|
|
58
|
+
expect(xml).toContain('id="xccdf_compliance-operator_rule_5.1.2"');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('maps state values to XCCDF result strings', () => {
|
|
62
|
+
const report = {
|
|
63
|
+
...baseReport,
|
|
64
|
+
results: [{
|
|
65
|
+
id: '1',
|
|
66
|
+
description: 'g',
|
|
67
|
+
checks: [
|
|
68
|
+
{
|
|
69
|
+
id: 'a', description: 'a', state: 'pass' as const
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'b', description: 'b', state: 'fail' as const
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'c', description: 'c', state: 'skip' as const
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'd', description: 'd', state: 'warn' as const
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'e', description: 'e', state: 'notApplicable' as const
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
}],
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const xml = generateXCCDF({ report, benchmarkVersion: 'cis-1.7' });
|
|
88
|
+
|
|
89
|
+
expect(xml).toContain('<result>pass</result>');
|
|
90
|
+
expect(xml).toContain('<result>fail</result>');
|
|
91
|
+
expect(xml).toContain('<result>notselected</result>');
|
|
92
|
+
expect(xml).toContain('<result>informational</result>');
|
|
93
|
+
expect(xml).toContain('<result>notapplicable</result>');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('marks scored checks with severity=medium and weight=10; unscored as low and 0', () => {
|
|
97
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
98
|
+
|
|
99
|
+
expect(xml).toMatch(/id="xccdf_compliance-operator_rule_5\.1\.1"[^>]*severity="medium"/);
|
|
100
|
+
expect(xml).toMatch(/id="xccdf_compliance-operator_rule_5\.1\.1"[^>]*weight="10"/);
|
|
101
|
+
expect(xml).toMatch(/id="xccdf_compliance-operator_rule_5\.1\.2"[^>]*severity="low"/);
|
|
102
|
+
expect(xml).toMatch(/id="xccdf_compliance-operator_rule_5\.1\.2"[^>]*weight="0"/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('computes score as pass/total*100, formatted to one decimal', () => {
|
|
106
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
107
|
+
|
|
108
|
+
expect(xml).toMatch(/<score[^>]*maximum="100\.0"[^>]*>50\.0<\/score>/);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('returns score 0.0 when total is 0', () => {
|
|
112
|
+
const xml = generateXCCDF({
|
|
113
|
+
report: {
|
|
114
|
+
...baseReport, total: 0, pass: 0, results: [],
|
|
115
|
+
},
|
|
116
|
+
benchmarkVersion: 'cis-1.7',
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(xml).toMatch(/<score[^>]*>0\.0<\/score>/);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('uses report.nodes for <target> elements when no clusterName is set', () => {
|
|
123
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
124
|
+
|
|
125
|
+
expect(xml).toContain('<target>node-a</target>');
|
|
126
|
+
expect(xml).toContain('<target>node-b</target>');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('clusterName argument overrides metadata.clusterName and node-derived targets', () => {
|
|
130
|
+
const xml = generateXCCDF({
|
|
131
|
+
report: baseReport,
|
|
132
|
+
benchmarkVersion: 'cis-1.7',
|
|
133
|
+
metadata: { clusterName: 'from-metadata' },
|
|
134
|
+
clusterName: 'from-arg',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(xml).toContain('<target>from-arg</target>');
|
|
138
|
+
expect(xml).not.toContain('<target>from-metadata</target>');
|
|
139
|
+
expect(xml).not.toContain('<target>node-a</target>');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('falls back to "not-applicable" for missing target addresses and target facts', () => {
|
|
143
|
+
const xml = generateXCCDF({ report: baseReport, benchmarkVersion: 'cis-1.7' });
|
|
144
|
+
|
|
145
|
+
expect(xml).toContain('<target-address>not-applicable</target-address>');
|
|
146
|
+
expect(xml).toContain('<fact name="not-applicable" type="string">not-applicable</fact>');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('emits a single placeholder Group when results is empty', () => {
|
|
150
|
+
const xml = generateXCCDF({
|
|
151
|
+
report: {
|
|
152
|
+
version: '1.0', total: 0, pass: 0, results: [],
|
|
153
|
+
},
|
|
154
|
+
benchmarkVersion: 'cis-1.7',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(xml).toContain('<Group id="not-applicable">');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('uses STIG metadata to override rule id, version, severity, fix, check system, and CCI idents', () => {
|
|
161
|
+
const xml = generateXCCDF({
|
|
162
|
+
report: {
|
|
163
|
+
...baseReport,
|
|
164
|
+
results: [{
|
|
165
|
+
id: 'g1',
|
|
166
|
+
description: 'g',
|
|
167
|
+
checks: [{
|
|
168
|
+
id: 'V-254553-TLS-apiserver', description: 'STIG check', scored: true, state: 'pass',
|
|
169
|
+
}],
|
|
170
|
+
}],
|
|
171
|
+
},
|
|
172
|
+
benchmarkVersion: 'rke2-stig-1.31',
|
|
173
|
+
stigChecks: {
|
|
174
|
+
'V-254553': {
|
|
175
|
+
ruleId: 'SV-254553r1016525_rule', version: 'SV-254553r1016525_rule', severity: 'high', fixId: 'F-254553', checkId: 'C-254553', cci: ['CCI-000366'],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(xml).toContain('idref="SV-254553r1016525_rule_TLS-apiserver"');
|
|
181
|
+
expect(xml).toContain('severity="high"');
|
|
182
|
+
expect(xml).toContain('<ident system="http://cyber.mil/cci">CCI-000366</ident>');
|
|
183
|
+
expect(xml).toContain('fixref="F-254553"');
|
|
184
|
+
expect(xml).toContain('<check system="C-254553">');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('preserves the operator-style rule id when there is no STIG metadata', () => {
|
|
188
|
+
const xml = generateXCCDF({
|
|
189
|
+
report: baseReport,
|
|
190
|
+
benchmarkVersion: 'cis-1.7',
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(xml).toContain('id="xccdf_compliance-operator_rule_5.1.1"');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('xccdf util: generateXCCDFPerNode', () => {
|
|
198
|
+
const multiNodeReport = {
|
|
199
|
+
version: '1.0',
|
|
200
|
+
total: 3,
|
|
201
|
+
pass: 1,
|
|
202
|
+
nodes: { master: ['m-1'], node: ['w-1', 'w-2'] },
|
|
203
|
+
results: [{
|
|
204
|
+
id: '1.1',
|
|
205
|
+
description: 'Master Node Configuration',
|
|
206
|
+
checks: [{
|
|
207
|
+
id: '1.1.1',
|
|
208
|
+
description: 'master check',
|
|
209
|
+
scored: true,
|
|
210
|
+
state: 'pass' as const,
|
|
211
|
+
}],
|
|
212
|
+
}, {
|
|
213
|
+
id: '4.1',
|
|
214
|
+
description: 'Worker Node Configuration',
|
|
215
|
+
checks: [{
|
|
216
|
+
id: '4.1.1',
|
|
217
|
+
description: 'mixed check',
|
|
218
|
+
scored: true,
|
|
219
|
+
state: 'mixed' as const,
|
|
220
|
+
nodes: ['w-2'],
|
|
221
|
+
}, {
|
|
222
|
+
id: '4.1.2',
|
|
223
|
+
description: 'failing check',
|
|
224
|
+
scored: false,
|
|
225
|
+
state: 'fail' as const,
|
|
226
|
+
}],
|
|
227
|
+
}],
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
it('emits a single <target> equal to the hostname', () => {
|
|
231
|
+
const xml = generateXCCDFPerNode({
|
|
232
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(xml).toContain('<target>w-1</target>');
|
|
236
|
+
expect(xml).not.toContain('<target>w-2</target>');
|
|
237
|
+
expect(xml).not.toContain('<target>m-1</target>');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('assigns each per-node document a TestResult id suffixed with the hostname so co-loaded files do not collide', () => {
|
|
241
|
+
const a = generateXCCDFPerNode({
|
|
242
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
243
|
+
});
|
|
244
|
+
const b = generateXCCDFPerNode({
|
|
245
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-2', role: 'node',
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
expect(a).toContain('<TestResult id="xccdf_compliance-operator_testresult_1_w-1"');
|
|
249
|
+
expect(b).toContain('<TestResult id="xccdf_compliance-operator_testresult_1_w-2"');
|
|
250
|
+
expect(a).not.toContain('id="xccdf_compliance-operator_testresult_1_w-2"');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('emits every rule from the cluster report regardless of role', () => {
|
|
254
|
+
const workerXml = generateXCCDFPerNode({
|
|
255
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
256
|
+
});
|
|
257
|
+
const masterXml = generateXCCDFPerNode({
|
|
258
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'm-1', role: 'master',
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
[workerXml, masterXml].forEach((xml) => {
|
|
262
|
+
expect(xml).toContain('xccdf_compliance-operator_rule_1.1.1');
|
|
263
|
+
expect(xml).toContain('xccdf_compliance-operator_rule_4.1.1');
|
|
264
|
+
expect(xml).toContain('xccdf_compliance-operator_rule_4.1.2');
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('maps mixed-state checks to fail for dissenting hosts and pass for the rest', () => {
|
|
269
|
+
const dissenter = generateXCCDFPerNode({
|
|
270
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-2', role: 'node',
|
|
271
|
+
});
|
|
272
|
+
const compliant = generateXCCDFPerNode({
|
|
273
|
+
report: multiNodeReport, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(dissenter).toMatch(/idref="xccdf_compliance-operator_rule_4\.1\.1"[\s\S]*?<result>fail<\/result>/);
|
|
277
|
+
expect(compliant).toMatch(/idref="xccdf_compliance-operator_rule_4\.1\.1"[\s\S]*?<result>pass<\/result>/);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('treats mixed-state checks with no dissent list as pass for all nodes', () => {
|
|
281
|
+
const report = {
|
|
282
|
+
...multiNodeReport,
|
|
283
|
+
results: [{
|
|
284
|
+
id: '4.1',
|
|
285
|
+
description: 'g',
|
|
286
|
+
checks: [{
|
|
287
|
+
id: '4.1.9', description: 'm', state: 'mixed' as const,
|
|
288
|
+
}],
|
|
289
|
+
}],
|
|
290
|
+
};
|
|
291
|
+
const xml = generateXCCDFPerNode({
|
|
292
|
+
report, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(xml).toMatch(/idref="xccdf_compliance-operator_rule_4\.1\.9"[\s\S]*?<result>pass<\/result>/);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('recomputes pass count per node while preserving cluster total as the scoring denominator', () => {
|
|
299
|
+
const report = {
|
|
300
|
+
version: '1.0',
|
|
301
|
+
total: 2,
|
|
302
|
+
pass: 1,
|
|
303
|
+
nodes: { node: ['w-1', 'w-2'] },
|
|
304
|
+
results: [{
|
|
305
|
+
id: '1',
|
|
306
|
+
description: 'g',
|
|
307
|
+
checks: [
|
|
308
|
+
{
|
|
309
|
+
id: 'a', description: 'a', state: 'pass' as const
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: 'b', description: 'b', state: 'mixed' as const, nodes: ['w-2'],
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
}],
|
|
316
|
+
};
|
|
317
|
+
const compliant = generateXCCDFPerNode({
|
|
318
|
+
report, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
319
|
+
});
|
|
320
|
+
const dissenter = generateXCCDFPerNode({
|
|
321
|
+
report, benchmarkVersion: 'cis-1.7', hostname: 'w-2', role: 'node',
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
expect(compliant).toMatch(/<score[^>]*>100\.0<\/score>/);
|
|
325
|
+
expect(dissenter).toMatch(/<score[^>]*>50\.0<\/score>/);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('preserves full rule metadata (title, fixtext, idents, check) from the cluster report', () => {
|
|
329
|
+
const report = {
|
|
330
|
+
version: '1.0',
|
|
331
|
+
total: 1,
|
|
332
|
+
pass: 1,
|
|
333
|
+
nodes: { node: ['w-1'] },
|
|
334
|
+
results: [{
|
|
335
|
+
id: 'V-254554',
|
|
336
|
+
description: 'controller manager group',
|
|
337
|
+
checks: [{
|
|
338
|
+
id: 'V-254554',
|
|
339
|
+
description: 'use-service-account-credentials',
|
|
340
|
+
audit: '/bin/ps -fC kube-controller-manager',
|
|
341
|
+
remediation: 'set use-service-account-credentials=true',
|
|
342
|
+
scored: true,
|
|
343
|
+
state: 'pass' as const,
|
|
344
|
+
}],
|
|
345
|
+
}],
|
|
346
|
+
};
|
|
347
|
+
const xml = generateXCCDFPerNode({
|
|
348
|
+
report, benchmarkVersion: 'rke2-stig-1.31-rgs', hostname: 'w-1', role: 'node',
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
expect(xml).toContain('<Group id="V-254554">');
|
|
352
|
+
expect(xml).toContain('<check-content>/bin/ps -fC kube-controller-manager</check-content>');
|
|
353
|
+
expect(xml).toContain('set use-service-account-credentials=true');
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('passes through non-mixed states unchanged', () => {
|
|
357
|
+
const report = {
|
|
358
|
+
...multiNodeReport,
|
|
359
|
+
results: [{
|
|
360
|
+
id: '4.1',
|
|
361
|
+
description: 'g',
|
|
362
|
+
checks: [
|
|
363
|
+
{
|
|
364
|
+
id: 'a', description: 'a', state: 'pass' as const
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: 'b', description: 'b', state: 'fail' as const
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: 'c', description: 'c', state: 'skip' as const
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
id: 'd', description: 'd', state: 'warn' as const
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
id: 'e', description: 'e', state: 'notApplicable' as const
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
}],
|
|
380
|
+
};
|
|
381
|
+
const xml = generateXCCDFPerNode({
|
|
382
|
+
report, benchmarkVersion: 'cis-1.7', hostname: 'w-1', role: 'node',
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
expect(xml).toContain('<result>pass</result>');
|
|
386
|
+
expect(xml).toContain('<result>fail</result>');
|
|
387
|
+
expect(xml).toContain('<result>notselected</result>');
|
|
388
|
+
expect(xml).toContain('<result>informational</result>');
|
|
389
|
+
expect(xml).toContain('<result>notapplicable</result>');
|
|
390
|
+
});
|
|
391
|
+
});
|
package/utils/chart.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
import { compare } from '@shell/utils/version';
|
|
3
3
|
import { compatibleVersionsFor } from '@shell/store/catalog';
|
|
4
|
+
import {
|
|
5
|
+
CHART, REPO, REPO_TYPE, VERSION, DEPRECATED
|
|
6
|
+
} from '@shell/config/query-params';
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Compares two chart versions using SemVer logic, with special handling for Rancher's "up" build metadata.
|
|
@@ -80,3 +83,36 @@ export function getLatestCompatibleVersion(chart, workerOSs, showPrerelease) {
|
|
|
80
83
|
|
|
81
84
|
return (compatible.length ? compatible[0] : chart.versions[0]) || {};
|
|
82
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Builds the route URL for the standalone chart readme page.
|
|
89
|
+
*
|
|
90
|
+
* The helper maps chart context into query params so the readme page can fetch
|
|
91
|
+
* version info directly (instead of relying on local/session storage transfer).
|
|
92
|
+
*/
|
|
93
|
+
export function getStandaloneReadmeUrl(router, {
|
|
94
|
+
cluster,
|
|
95
|
+
repoType,
|
|
96
|
+
repoName,
|
|
97
|
+
chartName,
|
|
98
|
+
versionName,
|
|
99
|
+
deprecated,
|
|
100
|
+
showAppReadme = true,
|
|
101
|
+
hideReadmeFirstTitle = true,
|
|
102
|
+
} = {}) {
|
|
103
|
+
const { href } = router.resolve({
|
|
104
|
+
name: 'readme',
|
|
105
|
+
params: { cluster },
|
|
106
|
+
query: {
|
|
107
|
+
[REPO_TYPE]: repoType,
|
|
108
|
+
[REPO]: repoName,
|
|
109
|
+
[CHART]: chartName,
|
|
110
|
+
[VERSION]: versionName,
|
|
111
|
+
[DEPRECATED]: deprecated,
|
|
112
|
+
showAppReadme: String(showAppReadme),
|
|
113
|
+
hideReadmeFirstTitle: String(hideReadmeFirstTitle),
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return href;
|
|
118
|
+
}
|
package/utils/fleet.ts
CHANGED
|
@@ -33,6 +33,13 @@ function conditionIsTrue(conditions: Condition[] | undefined, type: string): boo
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
class Application {
|
|
36
|
+
/**
|
|
37
|
+
* gitrepos/helmops are already restricted to clusters in their own namespace
|
|
38
|
+
*
|
|
39
|
+
* this empty selector means all applicable clusters will be selected
|
|
40
|
+
*/
|
|
41
|
+
includeAllWorkgroupRule = { clusterSelector: { matchExpressions: [] } }
|
|
42
|
+
|
|
36
43
|
excludeHarvesterRule = {
|
|
37
44
|
clusterSelector: {
|
|
38
45
|
matchExpressions: [{
|
|
@@ -45,7 +52,7 @@ class Application {
|
|
|
45
52
|
},
|
|
46
53
|
};
|
|
47
54
|
|
|
48
|
-
getTargetMode(targets: Target[], namespace: string): TargetMode {
|
|
55
|
+
getTargetMode(targets: Target[], namespace: string, areHarvesterHostsVisible: boolean): TargetMode {
|
|
49
56
|
if (namespace === 'fleet-local') {
|
|
50
57
|
return 'local';
|
|
51
58
|
}
|
|
@@ -83,8 +90,11 @@ class Application {
|
|
|
83
90
|
return target;
|
|
84
91
|
});
|
|
85
92
|
|
|
86
|
-
// Check if targets contains only harvester rule after name normalizing
|
|
87
|
-
|
|
93
|
+
// Check if targets contains only harvester rule or no rule at all after name normalizing
|
|
94
|
+
// That means the ALL option has been selected previously
|
|
95
|
+
// one case for feature harvester-baremetal-container-workload ON
|
|
96
|
+
// and another for feature harvester-baremetal-container-workload OFF
|
|
97
|
+
if (isEqual(normalized, [this.includeAllWorkgroupRule]) || isEqual(normalized, [this.excludeHarvesterRule])) {
|
|
88
98
|
mode = 'all';
|
|
89
99
|
}
|
|
90
100
|
|