From 3b40ad3b0eacbaae7df4a824c5e6f6361a8b2a60 Mon Sep 17 00:00:00 2001 From: Tim Klemm Date: Thu, 9 Jan 2025 16:07:02 -0500 Subject: [PATCH] HPCC-31364: Improve work unit ID detection for WUQuery filtering Detect complete identifiers instead of looking only at the first 10 characters. Signed-off-by: Tim Klemm --- common/workunit/workunit.cpp | 27 ++++++++--- ecl/eclplus/main.cpp | 31 +++++++++--- testing/unittests/CMakeLists.txt | 2 + testing/unittests/wutests.cpp | 82 ++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 testing/unittests/wutests.cpp diff --git a/common/workunit/workunit.cpp b/common/workunit/workunit.cpp index 8e42207db59..bbe0159aede 100644 --- a/common/workunit/workunit.cpp +++ b/common/workunit/workunit.cpp @@ -14041,17 +14041,32 @@ extern WORKUNIT_API void gatherLibraryNames(StringArray &names, StringArray &unr } } +// Evaluates if wuid matches the pattern: +// firstChar # # # # # # # # "-" # # # # # # [ "-" #+ ] +// All other deviations from the pattern, including an incomplete match or the use of wildcard +// characters, will return false. bool looksLikeAWuid(const char * wuid, const char firstChar) { if (!wuid) return false; - if (wuid[0] != firstChar) + // pattern match required content + if ((toupper(wuid[0]) != toupper(firstChar)) || + !isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4]) || + !isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8]) || + ('-' != wuid[9]) || + !isdigit(wuid[10]) || !isdigit(wuid[11]) || !isdigit(wuid[12]) || + !isdigit(wuid[13]) || !isdigit(wuid[14]) || !isdigit(wuid[15])) return false; - if (!isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4])) - return false; - if (!isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8])) - return false; - return (wuid[9]=='-'); + // pattern match optional content + size_t idx = 16; + if ('-' == wuid[16] && isdigit(wuid[17])) + { + idx += 2; + while (isdigit(wuid[idx])) + idx++; + } + // expect the NULL terminator + return ('\0' == wuid[idx]); } IPropertyTree * resolveDefinitionInArchive(IPropertyTree * archive, const char * path) diff --git a/ecl/eclplus/main.cpp b/ecl/eclplus/main.cpp index b48b6ece25c..693e64930fb 100644 --- a/ecl/eclplus/main.cpp +++ b/ecl/eclplus/main.cpp @@ -35,20 +35,37 @@ #define ERROR_NO_SERVER 3 #define ERROR_CODE_USAGE 4 -//copied from workunit.dll to avoid a dependency. Should possibly go in jlib. +// Evaluates if wuid matches the pattern: +// 'W' # # # # # # # # "-" # # # # # # [ "-" #+ ] +// All other deviations from the pattern, including an incomplete match or the use of wildcard +// characters, will return false. +// +// Copied from workunit.dll to avoid a dependency. Should possibly go in jlib. static bool localLooksLikeAWuid(const char * wuid) { if (!wuid) return false; - if (wuid[0] != 'W') + // pattern match required content + if ((toupper(wuid[0]) != 'W') || + !isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4]) || + !isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8]) || + ('-' != wuid[9]) || + !isdigit(wuid[10]) || !isdigit(wuid[11]) || !isdigit(wuid[12]) || + !isdigit(wuid[13]) || !isdigit(wuid[14]) || !isdigit(wuid[15])) return false; - if (!isdigit(wuid[1]) || !isdigit(wuid[2]) || !isdigit(wuid[3]) || !isdigit(wuid[4])) - return false; - if (!isdigit(wuid[5]) || !isdigit(wuid[6]) || !isdigit(wuid[7]) || !isdigit(wuid[8])) - return false; - return (wuid[9]=='-'); + // pattern match optional content + size_t idx = 16; + if ('-' == wuid[16] && isdigit(wuid[17])) + { + idx += 2; + while (isdigit(wuid[idx])) + idx++; + } + // expect the NULL terminator + return ('\0' == wuid[idx]); } + void usage() { printf("eclplus action=[list|view|dump|delete|abort|query|graph]\n"); diff --git a/testing/unittests/CMakeLists.txt b/testing/unittests/CMakeLists.txt index ee8278a30c3..c571acbd991 100644 --- a/testing/unittests/CMakeLists.txt +++ b/testing/unittests/CMakeLists.txt @@ -47,6 +47,7 @@ set ( SRCS fxpptests.cpp espapicmdtests.cpp filetests.cpp + wutests.cpp ${HPCC_SOURCE_DIR}/esp/bindings/SOAP/xpp/fxpp/FragmentedXmlPullParser.cpp ${HPCC_SOURCE_DIR}/esp/bindings/SOAP/xpp/fxpp/FragmentedXmlAssistant.cpp ${CMAKE_BINARY_DIR}/generated/ws_loggingservice_esp.cpp @@ -86,6 +87,7 @@ include_directories ( ${HPCC_SOURCE_DIR}/rtl/eclrtl ${HPCC_SOURCE_DIR}/rtl/include ${HPCC_SOURCE_DIR}/common/dllserver + ${HPCC_SOURCE_DIR}/common/workunit ${HPCC_SOURCE_DIR}/ecl/hql ${HPCC_SOURCE_DIR}/esp/bindings ${HPCC_SOURCE_DIR}/esp/bindings/SOAP/xpp diff --git a/testing/unittests/wutests.cpp b/testing/unittests/wutests.cpp new file mode 100644 index 00000000000..7b509ef85fc --- /dev/null +++ b/testing/unittests/wutests.cpp @@ -0,0 +1,82 @@ +/*############################################################################## + + Copyright (C) 2025 HPCC Systems®. + + Licensed under the Apache License, Version 2.0 (the "License", 'W')); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +############################################################################## */ + +#ifdef _USE_CPPUNIT +#include "unittests.hpp" +#include "workunit.hpp" + +class wuTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( wuTests ); + CPPUNIT_TEST(testLooksLikeAWuid); + CPPUNIT_TEST_SUITE_END(); + +public: + wuTests(){} + + void testLooksLikeAWuid() + { + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should pass", looksLikeAWuid("w12345678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should pass", looksLikeAWuid("W12345678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should pass", looksLikeAWuid("w12345678-123456-1", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should pass", looksLikeAWuid("w12345678-123456-12", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid(nullptr, 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("x12345678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("wx2345678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w1x345678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12x45678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w123x5678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w1234x678-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345x78-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w123456x8-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w1234567x-123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678x123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-x23456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-1x3456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-12x456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-123x56", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-1234x6", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-12345x", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-123456x", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-123456-x", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-123456-1x", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("w12345678-123456-1wx", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W1", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W123", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W1234", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W123456", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W1234567", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-1", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-12", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-123", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-1234", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-12345", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("W12345678-123456-", 'W')); + CPPUNIT_ASSERT_MESSAGE("looksLikeAWuid should fail", !looksLikeAWuid("*", 'W')); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION( wuTests ); +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( wuTests, "wu" ); + +#endif // _USE_CPPUNIT