diff --git a/.werks/17299 b/.werks/17299 new file mode 100644 index 00000000000..c092178599a --- /dev/null +++ b/.werks/17299 @@ -0,0 +1,10 @@ +Title: Windows agent reports the version of custom exe plugin as n/a +Class: feature +Compatible: compat +Component: checks +Date: 1736844398 +Edition: cre +Level: 1 +Version: 2.2.0p39 + +For any exe plugin the version is reported as n/a. diff --git a/agents/wnx/src/engine/providers/agent_plugins.cpp b/agents/wnx/src/engine/providers/agent_plugins.cpp index cc35e43ff30..7208efe9ae4 100644 --- a/agents/wnx/src/engine/providers/agent_plugins.cpp +++ b/agents/wnx/src/engine/providers/agent_plugins.cpp @@ -18,29 +18,38 @@ using namespace std::string_literals; namespace cma::provider { namespace { -enum class FileType { ps1, cmd, vbs, py, other }; +enum class FileType { ps1, cmd, vbs, py, exe, other }; -size_t GetLength(std::ifstream &ifs) { - ifs.seekg(0, std::ios_base::end); - const auto length = ifs.tellg(); - ifs.seekg(0, std::ios_base::beg); - return static_cast(length); +std::optional GetLength(std::ifstream &ifs) { + try { + ifs.seekg(0, std::ios_base::end); + const auto length = ifs.tellg(); + ifs.seekg(0, std::ios_base::beg); + return {static_cast(length)}; + } catch (const std::ios_base::failure &e) { + XLOG::d("Can't get length exception '{}'", e.what()); + return {}; + } } std::string ReadFileToString(const fs::path &file) { std::string ret; std::ifstream ifs(file, std::ifstream::in); - if (ifs) { - const auto length = GetLength(ifs); - ret.resize(length); - ifs.read(ret.data(), static_cast(length)); - if (ifs.good() || ifs.eof()) { - return ret; - } - XLOG::d("Can't read '{}'", file.u8string()); - } else { + if (!ifs) { XLOG::d("Can't open '{}'", file.u8string()); + return {}; + } + const auto length = GetLength(ifs); + if (!length.has_value()) { + return {}; + } + + ret.resize(*length); + ifs.read(ret.data(), static_cast(*length)); + if (ifs.good() || ifs.eof()) { + return ret; } + XLOG::d("Can't read '{}'", file.u8string()); return {}; } @@ -55,6 +64,7 @@ std::string Marker(FileType file_type) { case FileType::py: return "__version__ = "s; case FileType::other: + case FileType::exe: return {}; } // unreachable @@ -63,24 +73,36 @@ std::string Marker(FileType file_type) { std::string FindVersionInfo(const fs::path &file, FileType file_type) { try { - std::string ret = ReadFileToString(file); - auto marker = Marker(file_type); - if (marker.empty()) { - XLOG::t("This file type '{}' is not supported", file); - return {}; - } - const auto offset = ret.find(marker); - if (offset == std::string::npos) { - return fmt::format("{}:CMK_VERSION = unversioned", file); - } - const auto end = ret.find('\n', offset); - if (end == std::string::npos) { - XLOG::t("This file type '{}' strange!", file); - return {}; + switch (file_type) { + case FileType::exe: + return fmt::format("{}:CMK_VERSION = n/a", file); + case FileType::ps1: + case FileType::cmd: // also bat + case FileType::py: + case FileType::vbs: { + const auto ret = ReadFileToString(file); + const auto marker = Marker(file_type); + if (marker.empty()) { + XLOG::t("This file type '{}' is not supported", file); + return {}; + } + const auto offset = ret.find(marker); + if (offset == std::string::npos) { + return fmt::format("{}:CMK_VERSION = unversioned", file); + } + const auto end = ret.find('\n', offset); + if (end == std::string::npos) { + XLOG::t("This file type '{}' strange!", file); + return {}; + } + auto version_text = ret.substr(offset + marker.length(), + end - offset - marker.length()); + return fmt::format("{}:CMK_VERSION = {}", file, version_text); + } + case FileType::other: + XLOG::t("This file type '{}' not supported", file); + return {}; } - auto version_text = ret.substr(offset + marker.length(), - end - offset - marker.length()); - return fmt::format("{}:CMK_VERSION = {}", file, version_text); } catch (const std::exception &e) { XLOG::d("Can't access '{}', exception '{}'", file.u8string(), e.what()); @@ -102,8 +124,7 @@ std::vector ScanDir(const fs::path &dir) { const std::unordered_map map = { {L".ps1", FileType::ps1}, {L".cmd", FileType::cmd}, {L".bat", FileType::cmd}, {L".vbs", FileType::vbs}, - {L".py", FileType::py}, - }; + {L".py", FileType::py}, {L".exe", FileType::exe}}; const auto type = map.contains(extension) ? map.at(extension) : FileType::other; auto version_text = FindVersionInfo(file, type); diff --git a/agents/wnx/watest/test-section_agent_plugins.cpp b/agents/wnx/watest/test-section_agent_plugins.cpp index 49f60f21c33..df5f9bcede8 100644 --- a/agents/wnx/watest/test-section_agent_plugins.cpp +++ b/agents/wnx/watest/test-section_agent_plugins.cpp @@ -57,6 +57,27 @@ TEST_F(AgentPluginsTest, File) { })); } +TEST_F(AgentPluginsTest, JustExe) { + auto ps_file = fs::path{cfg::GetUserPluginsDir()} / "empty.exe"; + tst::CreateTextFile(ps_file, ""); + auto rows = getRows(); + ASSERT_EQ(rows.size(), 4); + EXPECT_TRUE(std::ranges::any_of(rows, [&](const std::string &row) { + return row == fmt::format("{}:CMK_VERSION = n/a", ps_file); + })); +} + +TEST_F(AgentPluginsTest, DISABLED_Exe) { + // Test is disabled because we need a binary to build: not appropriate for + // unit testing. You may enable this test manually + auto v_file = tst::GetSolutionRoot() / "test_files" / "tools" / "v" / + "target" / "release" / "v.exe"; + fs::copy(v_file, fs::path{cfg::GetUserPluginsDir()} / "mk-sql.exe"); + auto rows = getRows(); + ASSERT_EQ(rows.size(), 4); + EXPECT_TRUE(rows[3].ends_with("v.exe:CMK_VERSION = \"0.1.0\"")); +} + TEST_F(AgentPluginsTest, FileMix) { const std::vector> to_create = {