!73 同步master分支内容

From: @rabbitali 
Reviewed-by: @zhu-yuncheng 
Signed-off-by: @zhu-yuncheng
This commit is contained in:
openeuler-ci-bot 2023-09-13 08:52:51 +00:00 committed by Gitee
commit e6935b62e2
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
9 changed files with 231 additions and 654 deletions

View File

@ -1,49 +0,0 @@
From 83752eec95b4aff92786d09b6291700ed0c405a1 Mon Sep 17 00:00:00 2001
From: rabbitali <shusheng.wen@outlook.com>
Date: Tue, 29 Aug 2023 21:35:08 +0800
Subject: [PATCH] the problem of repeated display of vulnerabilities fixed by hot patches
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ceres/manages/vulnerability_manage.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/ceres/manages/vulnerability_manage.py b/ceres/manages/vulnerability_manage.py
index 3f85d3d..747df61 100644
--- a/ceres/manages/vulnerability_manage.py
+++ b/ceres/manages/vulnerability_manage.py
@@ -435,6 +435,7 @@ class VulnerabilityManage:
if not applied_hotpatch_info_list:
return result
+ record_key_set = {}
for cve_id, patch_name, hotpatch_status in applied_hotpatch_info_list:
rpm = patch_name.split("-", 1)[0]
# Refer to this example, the CVE can be marked as fixed only if all hotpatch are applied.
@@ -442,7 +443,12 @@ class VulnerabilityManage:
# CVE-2023-1111 redis-6.2.5-1/ACC-1-1/redis-benchmark ACTIVED
# CVE-2023-1111 redis-6.2.5-1/ACC-1-1/redis-cli ACTIVED
# CVE-2023-1111 redis-6.2.5-1/ACC-1-1/redis-server NOT-APPLIED
- if f"{cve_id}-{rpm}" not in self.available_hotpatch_key_set and hotpatch_status in ("ACTIVED", "ACCEPTED"):
+ record_key = f"{cve_id}-{rpm}"
+ if (
+ (record_key not in self.available_hotpatch_key_set)
+ and (hotpatch_status in ("ACTIVED", "ACCEPTED"))
+ and record_key not in record_key_set
+ ):
result.append(
{
"cve_id": cve_id,
@@ -451,6 +457,7 @@ class VulnerabilityManage:
"hp_status": hotpatch_status,
}
)
+ record_key_set.add(record_key)
return result
def cve_fix(self, unfixed_cve_info: dict) -> Tuple[str, dict]:
--
2.33.0

View File

@ -0,0 +1,64 @@
From d6be0a82ace5d07d31a91a628369f71534834441 Mon Sep 17 00:00:00 2001
From: rabbitali <shusheng.wen@outlook.com>
Date: Wed, 13 Sep 2023 10:58:16 +0800
Subject: [PATCH 1/1] update func named set_hotpatch_status_by_dnf_plugin
---
ceres/manages/vulnerability_manage.py | 30 ++++++++++++++++++++-------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/ceres/manages/vulnerability_manage.py b/ceres/manages/vulnerability_manage.py
index f45c1f2..ab4b41c 100644
--- a/ceres/manages/vulnerability_manage.py
+++ b/ceres/manages/vulnerability_manage.py
@@ -615,12 +615,11 @@ class VulnerabilityManage:
if not self.takeover and self.accepted:
try:
hotpatch_name = hotpatch_pkg.rsplit(".", 1)[0].split("-", 1)[1]
- status_set_result, log = self._set_hotpatch_status_by_dnf_plugin(hotpatch_name, "accept")
- if not status_set_result:
- stdout += "\n" + log
+ _, log = self._set_hotpatch_status_by_dnf_plugin(hotpatch_name, "accept")
+ stdout += f"\n\n{log}"
except IndexError as error:
LOGGER.error(error)
- stdout += "\n" + "hotpatch status set failed due to can't get correct hotpatch name!"
+ stdout += f"\n\nhotpatch status set failed due to can't get correct hotpatch name!"
return TaskExecuteRes.SUCCEED, stdout
@@ -637,12 +636,27 @@ class VulnerabilityManage:
Tuple[bool, str]
a tuple containing two elements (operation result, operation log).
"""
- code, stdout, stderr = execute_shell_command(f"dnf hotpatch --{operation} {hotpatch}")
- if code != CommandExitCode.SUCCEED:
+
+ # replace -ACC to /ACC or -SGL to /SGL
+ # Example: kernel-5.10.0-153.12.0.92.oe2203sp2-ACC-1-1 >> kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1
+ wait_to_remove_patch = re.sub(r'-(ACC|SGL)', r'/\1', hotpatch)
+ # Example of command execution result:
+ # Succeed:
+ # [root@openEuler ~]# dnf hotpatch --remove kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1
+ # Last metadata expiration check: 3:24:16 ago on Wed 13 Sep 2023 08:16:17 AM CST.
+ # Gonna remove this hot patch: kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1
+ # remove hot patch 'kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1' succeed
+ # Fail:
+ # [root@openEuler ~]# dnf hotpatch --accept kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1
+ # Last metadata expiration check: 3:25:24 ago on Wed 13 Sep 2023 08:16:17 AM CST.
+ # Gonna accept this hot patch: kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1
+ # accept hot patch 'kernel-5.10.0-153.12.0.92.oe2203sp2/ACC-1-1' failed, remain original status
+ code, stdout, stderr = execute_shell_command(f"dnf hotpatch --{operation} {wait_to_remove_patch}")
+ if code != CommandExitCode.SUCCEED or 'failed' in stdout:
LOGGER.error(f"hotpatch {hotpatch} set status failed!")
- return False, stderr
+ return False, stdout + stderr
- return True, stdout
+ return True, stdout + stderr
def cve_rollback(self, cves: List[dict]) -> Tuple[str, list]:
"""
--
2.33.0

View File

@ -0,0 +1,155 @@
From b0f71927a3bdb3096757ca8cdedb233d2b886a4d Mon Sep 17 00:00:00 2001
From: smjiao <smjiao@isoftstone.com>
Date: Thu, 7 Sep 2023 16:28:49 +0800
Subject: [PATCH] add file sync func
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ceres/__main__.py | 6 ++++
ceres/function/command.py | 11 ++++++++
ceres/function/schema.py | 12 ++++++++
ceres/manages/sync_manage.py | 55 ++++++++++++++++++++++++++++++++++++
4 files changed, 84 insertions(+)
create mode 100644 ceres/manages/sync_manage.py
diff --git a/ceres/__main__.py b/ceres/__main__.py
index d1bbee3..a93ec49 100644
--- a/ceres/__main__.py
+++ b/ceres/__main__.py
@@ -17,6 +17,7 @@ from ceres.function.command import (
cve_command_manage,
plugin_command_manage,
register_on_manager,
+ sync_conf_manage,
)
from ceres.function.log import LOGGER
@@ -55,6 +56,11 @@ def main():
cve_group.add_argument("--rollback", type=str)
subparsers_cve.set_defaults(function=cve_command_manage)
+ subparsers_sync = subparsers.add_parser("sync", help='sync conf file')
+ sync_group = subparsers_sync.add_mutually_exclusive_group(required=True)
+ sync_group.add_argument("--conf", type=str)
+ subparsers_sync.set_defaults(function=sync_conf_manage)
+
args = parser.parse_args()
try:
args.function(args)
diff --git a/ceres/function/command.py b/ceres/function/command.py
index e4d367a..7324f23 100644
--- a/ceres/function/command.py
+++ b/ceres/function/command.py
@@ -25,11 +25,13 @@ from ceres.function.schema import (
HOST_INFO_SCHEMA,
REPO_SET_SCHEMA,
STRING_ARRAY,
+ CONF_SYNC_SCHEMA,
)
from ceres.function.status import SUCCESS, StatusCode
from ceres.function.util import convert_string_to_json, get_dict_from_file, plugin_status_judge, validate_data
from ceres.manages import plugin_manage
from ceres.manages.collect_manage import Collect
+from ceres.manages.sync_manage import SyncManage
from ceres.manages.vulnerability_manage import VulnerabilityManage
@@ -191,3 +193,12 @@ def cve_command_manage(args):
else:
print("Please check the input parameters!")
exit(1)
+
+
+def sync_conf_manage(args):
+ if args.conf:
+ config = convert_string_to_json(args.conf)
+ if not validate_data(config, CONF_SYNC_SCHEMA):
+ exit(1)
+ res = StatusCode.make_response_body(SyncManage.sync_contents_to_conf(config))
+ print(json.dumps(res))
diff --git a/ceres/function/schema.py b/ceres/function/schema.py
index ada35c3..794152d 100644
--- a/ceres/function/schema.py
+++ b/ceres/function/schema.py
@@ -113,3 +113,15 @@ CVE_ROLLBACK_SCHEMA = {
}
},
}
+
+CONF_SYNC_SCHEMA = {
+ "type": "object",
+ "required": [
+ "file_path",
+ "content"
+ ],
+ "properties": {
+ "file_path": {"type": "string", "minLength": 1},
+ "content": {"type": "string", "minLength": 1}
+ }
+}
diff --git a/ceres/manages/sync_manage.py b/ceres/manages/sync_manage.py
new file mode 100644
index 0000000..9be2a47
--- /dev/null
+++ b/ceres/manages/sync_manage.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python3
+# ******************************************************************************
+# Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+# licensed under the Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+# http://license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN 'AS IS' BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+# PURPOSE.
+# See the Mulan PSL v2 for more details.
+# ******************************************************************************/
+# Author: Lay
+# Description: default
+# Date: 2023/6/14 16:31
+import os
+from ceres.function.log import LOGGER
+from ceres.function.status import (
+ FILE_NOT_FOUND,
+ UNKNOWN_ERROR,
+ SUCCESS
+)
+
+
+class SyncManage:
+ """
+ Sync managed conf to the host
+ """
+
+ @staticmethod
+ def sync_contents_to_conf(config: dict) -> str:
+ """
+ Write conf into file
+ Args:
+ config(dict): filepath and content for file sync, only. eg:
+ {
+ "file_path" = "/tmp/test"
+ "content" = "contents for this file"
+ }
+ Returns:
+ str: status code
+ """
+ file_path = config.get('file_path')
+
+ contents = config.get('content')
+ lines = contents.split('\n')
+ try:
+ with open(file_path, "w", encoding="utf-8") as file:
+ for line in lines:
+ file.write(line + "\n")
+ except Exception as e:
+ LOGGER.error("write sync content to conf failed, with msg{}".format(e))
+ return UNKNOWN_ERROR
+
+ return SUCCESS
--
Gitee

View File

@ -1,279 +0,0 @@
From 01c845220663a2572b6559bc25b52da1b2863256 Mon Sep 17 00:00:00 2001
From: rabbitali <shusheng.wen@outlook.com>
Date: Wed, 30 Aug 2023 10:59:52 +0800
Subject: [PATCH 1/1] update query disk info func
---
ceres/manages/collect_manage.py | 38 ++---
ceres/tests/manages/test_collect_manage.py | 163 +++++++++++++++++----
2 files changed, 152 insertions(+), 49 deletions(-)
diff --git a/ceres/manages/collect_manage.py b/ceres/manages/collect_manage.py
index 3472903..145d6dc 100644
--- a/ceres/manages/collect_manage.py
+++ b/ceres/manages/collect_manage.py
@@ -17,6 +17,7 @@ import pwd
import re
from socket import AF_INET, SOCK_DGRAM, socket
from typing import Any, Dict, List, Union
+import xml.etree.ElementTree as ET
from ceres.conf.constant import (
HOST_COLLECT_INFO_SUPPORT,
@@ -305,30 +306,33 @@ class Collect:
}
]
"""
- code, stdout, _ = execute_shell_command("lshw -json -c disk")
+ code, stdout, _ = execute_shell_command("lshw -xml -c disk")
if code != CommandExitCode.SUCCEED:
LOGGER.error(stdout)
return []
- # Convert the command result to a json string
- # lshw_data e.g "{...},{...},{...}"
- lshw_data = f"[{stdout}]"
-
try:
- disk_info_list = json.loads(lshw_data)
- except json.decoder.JSONDecodeError:
- LOGGER.warning("Json conversion error, " "please check command 'lshw -json -c disk'")
- disk_info_list = []
+ tree = ET.ElementTree(ET.fromstring(stdout))
+ except ET.ParseError as error:
+ LOGGER.error(error)
+ LOGGER.warning("disk info parse error, please check command 'lshw -xml -c disk'")
+ return []
+
+ disk_list = tree.findall("node")
+
+ if not disk_list:
+ return []
res = []
- if disk_info_list:
- for disk_info in disk_info_list:
- res.append(
- {
- "model": disk_info.get('description') or disk_info.get('product'),
- "capacity": f"{disk_info.get('size', 0) // 10 ** 9}GB",
- }
- )
+ for node in disk_list:
+ model = node.find("description") if node.find("product") is None else node.find("product")
+ size = node.find("size")
+ res.append(
+ {
+ "model": model.text if model is not None else "unknown",
+ "capacity": f"{int(size.text) / (1024**3)} GB" if size is not None else "unknown",
+ }
+ )
return res
diff --git a/ceres/tests/manages/test_collect_manage.py b/ceres/tests/manages/test_collect_manage.py
index b27af55..243aa4c 100644
--- a/ceres/tests/manages/test_collect_manage.py
+++ b/ceres/tests/manages/test_collect_manage.py
@@ -17,6 +17,7 @@ import pwd
import unittest
import warnings
from unittest import mock
+import xml.etree.ElementTree as ET
from ceres.conf.constant import CommandExitCode
from ceres.manages.collect_manage import Collect
@@ -454,60 +455,158 @@ class TestCollectManage(unittest.TestCase):
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_succeed_and_only_contain_description(
self, mock_execute_shell_command
):
- mock_execute_shell_command.return_value = (
- CommandExitCode.SUCCEED,
- '{"description": "ATA Disk", "size": 42949672960}',
- "",
- )
- self.assertEqual([{"model": "ATA Disk", "capacity": "42GB"}], Collect()._get_disk_info())
+ cmd_output = """<?xml version="1.0" standalone="yes" ?>
+<!-- generated by lshw-B.012.18 -->
+<!-- GCC 7.3.0 -->
+<!-- Linux 4.19.90-2003.4.0.0036.oe1.x86_64 #1 SMP Mon Mar 23 19:10:41 UTC 2020 x86_64 -->
+<!-- GNU libc 2 (glibc 2.28) -->
+<list>
+ <node id="virtio3" claimed="true" class="disk">
+ <description>Virtual I/O device</description>
+ <physid>0</physid>
+ <businfo>virtio@3</businfo>
+ <logicalname>/dev/vda</logicalname>
+ <size units="bytes">42949672960</size>
+ <configuration>
+ <setting id="driver" value="virtio_blk" />
+ <setting id="logicalsectorsize" value="512" />
+ <setting id="sectorsize" value="512" />
+ <setting id="signature" value="64860148" />
+ </configuration>
+ <capabilities>
+ <capability id="partitioned" >Partitioned disk</capability>
+ <capability id="partitioned:dos" >MS-DOS partition table</capability>
+ </capabilities>
+ <hints>
+ <hint name="icon" value="disc" />
+ </hints>
+ </node>
+</list>
+"""
+ mock_execute_shell_command.return_value = CommandExitCode.SUCCEED, cmd_output, ""
+ self.assertEqual([{"model": "Virtual I/O device", "capacity": "40.0 GB"}], Collect()._get_disk_info())
@mock.patch('ceres.manages.collect_manage.execute_shell_command')
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_succeed_and_has_no_description_or_product(
self, mock_execute_shell_command
):
- mock_execute_shell_command.return_value = (
- CommandExitCode.SUCCEED,
- '{"size": 42949672960}',
- "",
- )
- self.assertEqual([{"model": None, "capacity": "42GB"}], Collect()._get_disk_info())
+ cmd_output = """<?xml version="1.0" standalone="yes" ?>
+<!-- generated by lshw-B.012.18 -->
+<!-- GCC 7.3.0 -->
+<!-- Linux 4.19.90-2003.4.0.0036.oe1.x86_64 #1 SMP Mon Mar 23 19:10:41 UTC 2020 x86_64 -->
+<!-- GNU libc 2 (glibc 2.28) -->
+<list>
+ <node id="virtio3" claimed="true" class="disk">
+ <physid>0</physid>
+ <businfo>virtio@3</businfo>
+ <logicalname>/dev/vda</logicalname>
+ <size units="bytes">42949672960</size>
+ <configuration>
+ <setting id="driver" value="virtio_blk" />
+ <setting id="logicalsectorsize" value="512" />
+ <setting id="sectorsize" value="512" />
+ <setting id="signature" value="64860148" />
+ </configuration>
+ <capabilities>
+ <capability id="partitioned" >Partitioned disk</capability>
+ <capability id="partitioned:dos" >MS-DOS partition table</capability>
+ </capabilities>
+ <hints>
+ <hint name="icon" value="disc" />
+ </hints>
+ </node>
+</list>
+"""
+ mock_execute_shell_command.return_value = CommandExitCode.SUCCEED, cmd_output, ""
+ self.assertEqual([{"model": "unknown", "capacity": "40.0 GB"}], Collect()._get_disk_info())
@mock.patch('ceres.manages.collect_manage.execute_shell_command')
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_succeed_and_contain_description_and_product(
self, mock_execute_shell_command
):
- mock_execute_shell_command.return_value = (
- CommandExitCode.SUCCEED,
- '{"description": "ATA Disk", "size": 42949672960,"product": "MOCK PRODUCT"}',
- "",
- )
- self.assertEqual([{"model": "ATA Disk", "capacity": "42GB"}], Collect()._get_disk_info())
+ cmd_output = """<?xml version="1.0" standalone="yes" ?>
+<!-- generated by lshw-B.012.18 -->
+<!-- GCC 7.3.0 -->
+<!-- Linux 4.19.90-2003.4.0.0036.oe1.x86_64 #1 SMP Mon Mar 23 19:10:41 UTC 2020 x86_64 -->
+<!-- GNU libc 2 (glibc 2.28) -->
+<list>
+ <node id="virtio3" claimed="true" class="disk">
+ <description>Virtual I/O device</description>
+ <product>ATA Disk</product>
+ <physid>0</physid>
+ <businfo>virtio@3</businfo>
+ <logicalname>/dev/vda</logicalname>
+ <size units="bytes">42949672960</size>
+ <configuration>
+ <setting id="driver" value="virtio_blk" />
+ <setting id="logicalsectorsize" value="512" />
+ <setting id="sectorsize" value="512" />
+ <setting id="signature" value="64860148" />
+ </configuration>
+ <capabilities>
+ <capability id="partitioned" >Partitioned disk</capability>
+ <capability id="partitioned:dos" >MS-DOS partition table</capability>
+ </capabilities>
+ <hints>
+ <hint name="icon" value="disc" />
+ </hints>
+ </node>
+</list>
+"""
+ mock_execute_shell_command.return_value = CommandExitCode.SUCCEED, cmd_output, ""
+ self.assertEqual([{"model": "ATA Disk", "capacity": "40.0 GB"}], Collect()._get_disk_info())
@mock.patch('ceres.manages.collect_manage.execute_shell_command')
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_succeed_and_only_contain_product(
self, mock_execute_shell_command
):
- mock_execute_shell_command.return_value = (
- CommandExitCode.SUCCEED,
- '{"product": "MOCK PRODUCT", "size": 42949672960}',
- "",
- )
- self.assertEqual([{"model": "MOCK PRODUCT", "capacity": "42GB"}], Collect()._get_disk_info())
+ cmd_output = """<?xml version="1.0" standalone="yes" ?>
+<!-- generated by lshw-B.012.18 -->
+<!-- GCC 7.3.0 -->
+<!-- Linux 4.19.90-2003.4.0.0036.oe1.x86_64 #1 SMP Mon Mar 23 19:10:41 UTC 2020 x86_64 -->
+<!-- GNU libc 2 (glibc 2.28) -->
+<list>
+ <node id="virtio3" claimed="true" class="disk">
+ <product>MOCK PRODUCT</product>
+ <physid>0</physid>
+ <businfo>virtio@3</businfo>
+ <logicalname>/dev/vda</logicalname>
+ <size units="bytes">42949672960</size>
+ <configuration>
+ <setting id="driver" value="virtio_blk" />
+ <setting id="logicalsectorsize" value="512" />
+ <setting id="sectorsize" value="512" />
+ <setting id="signature" value="64860148" />
+ </configuration>
+ <capabilities>
+ <capability id="partitioned" >Partitioned disk</capability>
+ <capability id="partitioned:dos" >MS-DOS partition table</capability>
+ </capabilities>
+ <hints>
+ <hint name="icon" value="disc" />
+ </hints>
+ </node>
+</list>
+"""
+ mock_execute_shell_command.return_value = CommandExitCode.SUCCEED, cmd_output, ""
+ self.assertEqual([{"model": "MOCK PRODUCT", "capacity": "40.0 GB"}], Collect()._get_disk_info())
@mock.patch('ceres.manages.collect_manage.execute_shell_command')
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_fail(self, mock_execute_shell_command):
mock_execute_shell_command.return_value = CommandExitCode.FAIL, "", ""
self.assertEqual([], Collect()._get_disk_info())
- @mock.patch.object(json, "loads")
+ @mock.patch.object(ET, "ElementTree")
@mock.patch('ceres.manages.collect_manage.execute_shell_command')
def test_get_disk_info_should_return_disk_info_when_shell_command_execute_succeed_but_decode_error(
- self, mock_execute_shell_command, mock_json_loads
+ self, mock_execute_shell_command, mock_parse_xml
):
- mock_execute_shell_command.return_value = (
- CommandExitCode.SUCCEED,
- '{"product": "MOCK PRODUCT", "size": 42949672960}',
- "",
- )
- mock_json_loads.side_effect = json.decoder.JSONDecodeError('', '', int())
+ mock_cmd_output = """<?xml version="1.0" standalone="yes" ?>
+<!-- generated by lshw-B.012.18 -->
+<!-- GCC 7.3.0 -->
+<!-- Linux 4.19.90-2003.4.0.0036.oe1.x86_64 #1 SMP Mon Mar 23 19:10:41 UTC 2020 x86_64 -->
+<!-- GNU libc 2 (glibc 2.28) -->
+"""
+ mock_execute_shell_command.return_value = CommandExitCode.SUCCEED, mock_cmd_output, ""
+ mock_parse_xml.side_effect = ET.ParseError
self.assertEqual([], Collect()._get_disk_info())
--
2.33.0

View File

@ -1,291 +0,0 @@
From d7d97d24c0b2b7e0f5686fc9f9bd1674c94c53eb Mon Sep 17 00:00:00 2001
From: rabbitali <shusheng.wen@outlook.com>
Date: Mon, 4 Sep 2023 17:06:06 +0800
Subject: [PATCH] adapted to cve rollback and update return value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ceres/conf/constant.py | 5 ++
ceres/function/status.py | 2 +
ceres/manages/vulnerability_manage.py | 114 ++++++++++++++------------
3 files changed, 68 insertions(+), 53 deletions(-)
diff --git a/ceres/conf/constant.py b/ceres/conf/constant.py
index 8c7723b..79594ae 100644
--- a/ceres/conf/constant.py
+++ b/ceres/conf/constant.py
@@ -70,3 +70,8 @@ REGISTER_HELP_INFO = """
class CommandExitCode:
SUCCEED = 0
FAIL = 255
+
+
+class TaskExecuteRes:
+ SUCCEED = "succeed"
+ FAIL = "fail"
diff --git a/ceres/function/status.py b/ceres/function/status.py
index 70fc212..d1fe088 100644
--- a/ceres/function/status.py
+++ b/ceres/function/status.py
@@ -25,6 +25,7 @@ REPO_CONTENT_INCORRECT = "Repo.Content.Incorrect"
REPO_NOT_SET = "Repo.Not.Set"
NO_COMMAND = "No.Command"
NOT_PATCH = "Not.Patch"
+PRE_CHECK_ERROR = "Pre.Check.Error"
COMMAND_EXEC_ERROR = "Command.Error"
@@ -49,6 +50,7 @@ class StatusCode:
NO_COMMAND: {"msg": "command not found"},
NOT_PATCH: {"msg": "no valid hot patch is matched"},
COMMAND_EXEC_ERROR: {"msg": "the input command is incorrect"},
+ PRE_CHECK_ERROR: {"msg": "Preset check item detection failed"},
}
@classmethod
diff --git a/ceres/manages/vulnerability_manage.py b/ceres/manages/vulnerability_manage.py
index 747df61..20bfe1e 100644
--- a/ceres/manages/vulnerability_manage.py
+++ b/ceres/manages/vulnerability_manage.py
@@ -16,19 +16,10 @@ import json
from collections import defaultdict
from typing import Dict, List, Tuple
-from ceres.conf.constant import REPO_ID_FOR_CVE_MANAGE, CommandExitCode
+from ceres.conf.constant import REPO_ID_FOR_CVE_MANAGE, CommandExitCode, TaskExecuteRes
from ceres.function.check import PreCheck
from ceres.function.log import LOGGER
-from ceres.function.status import (
- FAIL,
- NOT_PATCH,
- PARAM_ERROR,
- REPO_CONTENT_INCORRECT,
- REPO_NOT_SET,
- SUCCESS,
- StatusCode,
- COMMAND_EXEC_ERROR,
-)
+from ceres.function.status import *
from ceres.function.util import execute_shell_command
@@ -131,7 +122,7 @@ class VulnerabilityManage:
cve_scan_result["check_items"] = items_check_log
if not check_result:
LOGGER.info("The pre-check is failed before execute command!")
- return FAIL, cve_scan_result
+ return PRE_CHECK_ERROR, cve_scan_result
self.installed_rpm_info = self._query_installed_rpm()
self.available_rpm_info = self._query_available_rpm()
@@ -200,7 +191,7 @@ class VulnerabilityManage:
# kernel-debuginfo.x86_64 5.10.0-60.105.0.132.oe2203 update
# kernel-debugsource.x86_64 5.10.0-60.105.0.132.oe2203 update
# kernel-devel.x86_64 5.10.0-60.105.0.132.oe2203 update
- code, stdout, stderr = execute_shell_command("dnf list available")
+ code, stdout, stderr = execute_shell_command("dnf list available|grep -v '.src'")
if code != CommandExitCode.SUCCEED:
LOGGER.error(stderr)
return result
@@ -435,7 +426,7 @@ class VulnerabilityManage:
if not applied_hotpatch_info_list:
return result
- record_key_set = {}
+ record_key_set = set()
for cve_id, patch_name, hotpatch_status in applied_hotpatch_info_list:
rpm = patch_name.split("-", 1)[0]
# Refer to this example, the CVE can be marked as fixed only if all hotpatch are applied.
@@ -513,10 +504,10 @@ class VulnerabilityManage:
def gen_failed_result(cves: dict, log: str):
result = []
for cve in cves:
- cve_fix_result = {"cve_id": cve.get("cve_id"), "result": "failed", "rpms": []}
+ cve_fix_result = {"cve_id": cve.get("cve_id"), "result": TaskExecuteRes.FAIL, "rpms": []}
for rpm in cve.get("rpms"):
cve_fix_result["rpms"].append(
- {"installed_rpm": rpm.get("installed_rpm"), "result": "fail", "log": log}
+ {"installed_rpm": rpm.get("installed_rpm"), "result": TaskExecuteRes.FAIL, "log": log}
)
result.append(cve_fix_result)
return result
@@ -528,14 +519,14 @@ class VulnerabilityManage:
if not check_result:
LOGGER.info("The pre-check is failed before execute command!")
result["cves"] = gen_failed_result(unfixed_cve_info.get("cves"), "pre-check items check failed")
- return FAIL, result
+ return PRE_CHECK_ERROR, result
all_cve_fix_result, all_cve_fix_info = [], []
for cve_info in unfixed_cve_info.get("cves"):
rpms_fix_result, rpm_fix_result_list = [], []
for rpm_info in cve_info.get("rpms"):
update_result, log = self._update_rpm_by_dnf(rpm_info)
- rpms_fix_result.append(update_result == SUCCESS)
+ rpms_fix_result.append(update_result == TaskExecuteRes.SUCCEED)
rpm_fix_result_list.append(
{"installed_rpm": rpm_info.get("installed_rpm"), "result": update_result, "log": log}
)
@@ -544,13 +535,13 @@ class VulnerabilityManage:
all_cve_fix_info.append(
{
"cve_id": cve_info.get("cve_id"),
- "result": SUCCESS if all(rpms_fix_result) else FAIL,
+ "result": TaskExecuteRes.SUCCEED if all(rpms_fix_result) else TaskExecuteRes.FAIL,
"rpms": rpm_fix_result_list,
}
)
result.update({"cves": all_cve_fix_info})
- return SUCCESS if all(all_cve_fix_result) else FAIL, result
+ return TaskExecuteRes.SUCCEED if all(all_cve_fix_result) else TaskExecuteRes.FAIL, result
def _update_rpm_by_dnf(self, cve: dict) -> Tuple[str, str]:
"""
@@ -587,10 +578,10 @@ class VulnerabilityManage:
"""
code, stdout, stderr = execute_shell_command(f"dnf update {rpm_name} -y")
if code != CommandExitCode.SUCCEED:
- return FAIL, stderr
+ return TaskExecuteRes.FAIL, stderr
if "Complete" not in stdout:
- return FAIL, stdout
- return SUCCESS, stdout
+ return TaskExecuteRes.FAIL, stdout
+ return TaskExecuteRes.SUCCEED, stdout
def _update_hotpatch_by_dnf_plugin(self, hotpatch_pkg: str) -> Tuple[str, str]:
"""
@@ -611,10 +602,10 @@ class VulnerabilityManage:
code, stdout, stderr = execute_shell_command(update_command)
if code != CommandExitCode.SUCCEED:
- return FAIL, stderr
+ return TaskExecuteRes.FAIL, stderr
if "Apply hot patch succeed" not in stdout and "No hot patches marked for install" not in stdout:
- return FAIL, stdout
+ return TaskExecuteRes.FAIL, stdout
if not self.takeover and self.accepted:
try:
@@ -626,7 +617,7 @@ class VulnerabilityManage:
LOGGER.error(error)
stdout += "\n" + "hotpatch status set failed due to can't get correct hotpatch name!"
- return SUCCESS, stdout
+ return TaskExecuteRes.SUCCEED, stdout
@staticmethod
def _set_hotpatch_status_by_dnf_plugin(hotpatch: str, operation: str) -> Tuple[bool, str]:
@@ -703,25 +694,47 @@ class VulnerabilityManage:
log = "No valid hot patch is matched."
return NOT_PATCH, [dict(cve_id=cve["cve_id"], log=log, result="fail") for cve in cves]
- cmd_execute_result = []
- for base_pkg, hotpatch_cves in hotpatch_list.items():
- rollback_result, log = self._hotpatch_rollback(base_pkg)
- result = 'succeed' if rollback_result else 'fail'
- cmd_execute_result.extend([dict(cve_id=cve, log=log, result=result) for cve in hotpatch_cves])
+ wait_to_rollback_patch = []
+ for cve_info in cves:
+ wait_to_rollback_patch.extend(hotpatch_list.get(cve_info["cve_id"], []))
- not_rollback_cve = set([cve["cve_id"] for cve in cves]).difference(
- set([cve_info["cve_id"] for cve_info in cmd_execute_result])
- )
+ hotpatch_rollback_res = {}
+ for patch in set(wait_to_rollback_patch):
+ rollback_result, log = self._hotpatch_rollback(patch)
+ hotpatch_rollback_res[patch] = {
+ "result": TaskExecuteRes.SUCCEED if rollback_result else TaskExecuteRes.FAIL,
+ "log": log,
+ }
+
+ cve_rollback_result = []
+
+ for cve_info in cves:
+ if cve_info["cve_id"] not in hotpatch_list:
+ fail_result = {
+ "cve_id": cve_info["cve_id"],
+ "log": "No valid hot patch is matched."
+ if cve_info["hotpatch"]
+ else "Cold patch rollback is not supported.",
+ "result": "fail",
+ }
+ cve_rollback_result.append(fail_result)
+ else:
+ tmp_result_list = []
+ tmp_log = []
- if not_rollback_cve:
- for cve in [cve for cve in cves if cve["cve_id"] in not_rollback_cve]:
- if cve["hotpatch"]:
- log = "No valid hot patch is matched."
- else:
- log = "Cold patch rollback is not supported."
- cmd_execute_result.append(dict(cve_id=cve["cve_id"], log=log, result="fail"))
+ for patch in hotpatch_list.get(cve_info["cve_id"]):
+ tmp_result_list.append(hotpatch_rollback_res[patch]["result"] == TaskExecuteRes.SUCCEED)
+ tmp_log.append(hotpatch_rollback_res[patch]["log"])
- return SUCCESS, cmd_execute_result
+ cve_rollback_result.append(
+ {
+ "cve_id": cve_info["cve_id"],
+ "log": "\n".join(tmp_log),
+ "result": TaskExecuteRes.SUCCEED if all(tmp_result_list) else TaskExecuteRes.FAIL,
+ }
+ )
+
+ return SUCCESS, cve_rollback_result
@staticmethod
def _hotpatch_list_cve() -> dict:
@@ -731,15 +744,14 @@ class VulnerabilityManage:
Returns:
dict: e.g
{
- "base-pkg/hotpatch-1": [cve_id1,cveid2],
- "base-pkg/hotpatch-2": [cve_id1,cveid2]
+ "CVE-XXXX-XXX": ["patch 1", "patch 2"]
}
"""
# Run the dnf command to query the hotpatch list,e.g
# Last metadata expiration check:
- # CVE id base-pkg/hotpatch status
- # CVE-1 A-1.1-1/HP1 ACTIVED
- # CVE-2 A-1.1-1/HP1 ACTIVED
+ # CVE id base-pkg/hotpatch status
+ # CVE-1 A-1.1-1/ACC-1-1/binary_file1 ACTIVED
+ # CVE-2 A-1.1-1/ACC-1-1/binary_file2 ACTIVED
code, hotpatch_list_output, _ = execute_shell_command(f"dnf hotpatch --list cve")
if code != CommandExitCode.SUCCEED:
LOGGER.error(f"Failed to hotpatch list cve.")
@@ -754,7 +766,7 @@ class VulnerabilityManage:
cve_id, base_pkg, status = [info.strip() for info in hotpatch_info.split()]
if status != "ACTIVED" and status != "ACCEPTED":
continue
- hotpatch_list[base_pkg].append(cve_id)
+ hotpatch_list[cve_id].append(base_pkg)
return hotpatch_list
@@ -765,11 +777,7 @@ class VulnerabilityManage:
Args:
cve_id: cve is rolled back
"""
- execute_result, hotpatch_release_info = self._hotpatch_info(base_pkg_hotpatch)
- if not execute_result:
- return False, "Failed to query patch information."
-
- hotpatch_name = "patch-%s-%s-%s-%s" % tuple(base_pkg_hotpatch.split("/") + list(hotpatch_release_info.values()))
+ hotpatch_name = "patch-%s-%s" % tuple(base_pkg_hotpatch.rsplit("/", 2)[:2])
_, stdout, stderr = execute_shell_command(f"dnf remove {hotpatch_name} -y")
return True, stdout + stderr
--
Gitee

View File

@ -1,25 +0,0 @@
From 5a5304775690a2e05b138f5ba30dfbb3b00e9ca4 Mon Sep 17 00:00:00 2001
From: rabbitali <shusheng.wen@outlook.com>
Date: Tue, 5 Sep 2023 17:38:10 +0800
Subject: [PATCH 1/1] update field about cve fix return value
---
ceres/manages/vulnerability_manage.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ceres/manages/vulnerability_manage.py b/ceres/manages/vulnerability_manage.py
index 20bfe1e..540f051 100644
--- a/ceres/manages/vulnerability_manage.py
+++ b/ceres/manages/vulnerability_manage.py
@@ -541,7 +541,7 @@ class VulnerabilityManage:
)
result.update({"cves": all_cve_fix_info})
- return TaskExecuteRes.SUCCEED if all(all_cve_fix_result) else TaskExecuteRes.FAIL, result
+ return SUCCESS if all(all_cve_fix_result) else FAIL, result
def _update_rpm_by_dnf(self, cve: dict) -> Tuple[str, str]:
"""
--
2.33.0

Binary file not shown.

BIN
aops-ceres-v1.3.1.tar.gz Normal file

Binary file not shown.

View File

@ -1,14 +1,12 @@
Name: aops-ceres
Version: v1.3.0
Release: 5
Version: v1.3.1
Release: 3
Summary: An agent which needs to be adopted in client, it managers some plugins, such as gala-gopher(kpi collection), fluentd(log collection) and so on.
License: MulanPSL2
URL: https://gitee.com/openeuler/%{name}
Source0: %{name}-%{version}.tar.gz
Patch0001: 0001-fix-bug-repeated-display-of-vulnerabilities.patch
Patch0002: 0002-update-query-disk-info-func.patch
Patch0003: 0003-adapted-to-cve-rollback-and-update-return-value.patch
Patch0004: 0004-update-field-about-cve-fix-return-value.patch
Patch0001: 0001-update-func-named-set-hotpatch-status-by-dnf-plugin.patch
Patch0002: 0002-add-file-sync-func.patch
BuildRequires: python3-setuptools
Requires: python3-requests python3-jsonschema python3-libconf
@ -43,11 +41,15 @@ An agent which needs to be adopted in client, it managers some plugins, such as
%changelog
* Tue Sep 05 2023 wenxin<shusheng.wen@outlook.com> - v1.3.0-5
- adapted to cve rollback and update return value
* Wed Sep 13 2023 wenxin<shusheng.wen@outlook.com> - v1.3.1-3
- add file sync func
* Tue Sep 05 2023 wenxin<shusheng.wen@outlook.com> - v1.3.0-4
- adapted to cve rollback and update return value
* Wed Sep 13 2023 wenxin<shusheng.wen@outlook.com> - v1.3.1-2
- update func named set_hotpatch_status_by_dnf_plugin
* Mon Sep 11 2023 zhuyuncheng<zhu-yuncheng@huawei.com> - v1.3.1-1
- update rollback task logic, better returned log
- update status code and return None when installed_rpm or available_rpm is empty
* Wed Aug 30 2023 wenxin<shusheng.wen@outlook.com> - v1.3.0-3
- update query disk info func