From 0ded9a29ce88ce9da1b41407f42e8bae207875a7 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sat, 17 Feb 2024 12:30:35 +0000 Subject: [PATCH] [Test] Add tests for dynamic fuzzy keys --- .../cases/120_fuzzy/encrypted.robot | 8 +++ test/functional/cases/120_fuzzy/lib.robot | 16 ++++- test/functional/configs/fuzzy.conf | 1 + test/functional/configs/maps/fuzzy_keymap.map | 16 +++++ test/functional/lib/rspamd.py | 69 +++++++++++++++++-- 5 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 test/functional/configs/maps/fuzzy_keymap.map diff --git a/test/functional/cases/120_fuzzy/encrypted.robot b/test/functional/cases/120_fuzzy/encrypted.robot index 548ea8cb9..331fada2d 100644 --- a/test/functional/cases/120_fuzzy/encrypted.robot +++ b/test/functional/cases/120_fuzzy/encrypted.robot @@ -12,3 +12,11 @@ Fuzzy Fuzzy Fuzzy Miss Fuzzy Multimessage Miss Test + +Fuzzy Fuzzy Dynamic Key + Set Suite Variable ${RSPAMD_FUZZY_ENCRYPTION_KEY} "mbggdnw3tdx7r3ruakjecpf5hcqr4cb4nmdp1fxynx3drbyujb3y" + Fuzzy Multimessage Fuzzy Encrypted Test + +Fuzzy Fuzzy Another Dynamic Key + Set Suite Variable ${RSPAMD_FUZZY_ENCRYPTION_KEY} "c98d3pnb7ejjz1rkobumbbjzo5pbeh64rj68dudy8w7h8mipg1by" + Fuzzy Multimessage Fuzzy Encrypted Test diff --git a/test/functional/cases/120_fuzzy/lib.robot b/test/functional/cases/120_fuzzy/lib.robot index 02e0a0af5..bc0fdd51f 100644 --- a/test/functional/cases/120_fuzzy/lib.robot +++ b/test/functional/cases/120_fuzzy/lib.robot @@ -75,6 +75,15 @@ Fuzzy Fuzzy Test Expect Symbol ${FLAG1_SYMBOL} END +Fuzzy Encrypted Test + [Arguments] ${message} + @{path_info} = Path Splitter ${message} + @{fuzzy_files} = List Files In Directory ${pathinfo}[0] pattern=${pathinfo}[1].fuzzy* absolute=1 + FOR ${i} IN @{fuzzy_files} + ${result} = Run Rspamc -p -h ${RSPAMD_LOCAL_ADDR}:${RSPAMD_PORT_NORMAL} --key ${RSPAMD_FUZZY_ENCRYPTION_KEY} ${i} + Check Rspamc ${result} ${FLAG1_SYMBOL} + END + Fuzzy Miss Test [Arguments] ${message} Scan File ${message} @@ -105,7 +114,7 @@ Fuzzy Setup Encrypted Keyed [Arguments] ${algorithm} Set Suite Variable ${RSPAMD_FUZZY_ALGORITHM} ${algorithm} Set Suite Variable ${RSPAMD_FUZZY_ENCRYPTED_ONLY} true - Set Suite Variable ${RSPAMD_FUZZY_ENCRYPTION_KEY} ${RSPAMD_KEY_PUB1} + Set Suite Variable ${RSPAMD_FUZZY_ENCRYPTION_KEY} ${RSPAMD_KEY_PUB1} Set Suite Variable ${RSPAMD_FUZZY_KEY} mYN888sydwLTfE32g2hN Set Suite Variable ${RSPAMD_FUZZY_SHINGLES_KEY} hXUCgul9yYY3Zlk1QIT2 @@ -165,6 +174,11 @@ Fuzzy Multimessage Fuzzy Test Fuzzy Fuzzy Test ${i} END +Fuzzy Multimessage Fuzzy Encrypted Test + FOR ${i} IN @{MESSAGES} + Fuzzy Encrypted Test ${i} + END + Fuzzy Multimessage Miss Test FOR ${i} IN @{RANDOM_MESSAGES} Fuzzy Miss Test ${i} diff --git a/test/functional/configs/fuzzy.conf b/test/functional/configs/fuzzy.conf index 8af1cfa3f..f46faf6d4 100644 --- a/test/functional/configs/fuzzy.conf +++ b/test/functional/configs/fuzzy.conf @@ -60,6 +60,7 @@ worker { privkey = "{= env.KEY_PVT1 =}"; pubkey = "{= env.KEY_PUB1 =}"; } + dynamic_keys_map = "{= env.TESTDIR =}/configs/maps/fuzzy_keymap.map"; } fuzzy_check { diff --git a/test/functional/configs/maps/fuzzy_keymap.map b/test/functional/configs/maps/fuzzy_keymap.map new file mode 100644 index 000000000..df152a9c9 --- /dev/null +++ b/test/functional/configs/maps/fuzzy_keymap.map @@ -0,0 +1,16 @@ +[{ + privkey = "achyfduzs74yc1p95bk9apoknhtzn596pzeai5ybi5tftencoray"; + id = "xb66rsu7e5i3o95sr7ifd3rxgjruktn8ptsesdxrf4biyc5ckyu6zcye54pkw3cmkhbyoebow85bsqxhryfyy4eep5gai4x1a8s3u5d"; + pubkey = "mbggdnw3tdx7r3ruakjecpf5hcqr4cb4nmdp1fxynx3drbyujb3y"; + type = "kex"; + algorithm = "curve25519"; + encoding = "base32"; +}, +{ + privkey = "y1z16mw4n8eaefgwhgneyrntb8rxx911r4q7pgweb7t8sj1q8goy"; + id = "id8kmo7im37bszdoorpm6cjjg8saazz71bc9ijz974wip3gaockbpymb5e91r8cwsf7kmcbbbygap9bss8r3zkhth5i7pdnyazpkppy"; + pubkey = "zhypei8sartqrtow84dddgp5exh3gsr65kbw88wj7ppot1bwmuiy"; + type = "kex"; + algorithm = "curve25519"; + encoding = "base32"; +}] \ No newline at end of file diff --git a/test/functional/lib/rspamd.py b/test/functional/lib/rspamd.py index 3976ca949..76132ad5a 100644 --- a/test/functional/lib/rspamd.py +++ b/test/functional/lib/rspamd.py @@ -1,3 +1,29 @@ +# Copyright 2024 Vsevolod Stakhov +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# 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. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# 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. + from urllib.request import urlopen import glob import grp @@ -17,6 +43,7 @@ from robot.api import logger from robot.libraries.BuiltIn import BuiltIn import demjson + def Check_JSON(j): d = demjson.decode(j, strict=True) logger.debug('got json %s' % d) @@ -24,6 +51,7 @@ def Check_JSON(j): assert 'error' not in d return d + def check_json_log(fn): line_count = 0 f = open(fn, 'r') @@ -33,9 +61,11 @@ def check_json_log(fn): line_count = line_count + 1 assert line_count > 0 + def cleanup_temporary_directory(directory): shutil.rmtree(directory) + def save_run_results(directory, filenames): current_directory = os.getcwd() suite_name = BuiltIn().get_variable_value("${SUITE_NAME}") @@ -58,24 +88,29 @@ def save_run_results(directory, filenames): shutil.copy(source_file, "%s/%s" % (destination_directory, file)) shutil.copy(source_file, "%s/robot-save/%s.last" % (current_directory, file)) + def encode_filename(filename): return "".join(['%%%0X' % ord(b) for b in filename]) + def get_test_directory(): return os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "../../") + def get_top_dir(): if os.environ.get('RSPAMD_TOPDIR'): return os.environ['RSPAMD_TOPDIR'] return get_test_directory() + "/../../" + def get_install_root(): if os.environ.get('RSPAMD_INSTALLROOT'): return os.path.abspath(os.environ['RSPAMD_INSTALLROOT']) return os.path.abspath("../install/") + def get_rspamd(): if os.environ.get('RSPAMD'): return os.environ['RSPAMD'] @@ -84,6 +119,7 @@ def get_rspamd(): dname = get_top_dir() return dname + "/src/rspamd" + def get_rspamc(): if os.environ.get('RSPAMC'): return os.environ['RSPAMC'] @@ -92,6 +128,7 @@ def get_rspamc(): dname = get_top_dir() return dname + "/src/client/rspamc" + def get_rspamadm(): if os.environ.get('RSPAMADM'): return os.environ['RSPAMADM'] @@ -100,6 +137,7 @@ def get_rspamadm(): dname = get_top_dir() return dname + "/src/rspamadm/rspamadm" + def HTTP(method, host, port, path, data=None, headers={}): c = http.client.HTTPConnection("%s:%s" % (host, port)) c.request(method, path, data, headers) @@ -109,9 +147,11 @@ def HTTP(method, host, port, path, data=None, headers={}): c.close() return [s, t] + def hard_link(src, dst): os.link(src, dst) + def make_temporary_directory(): """Creates and returns a unique temporary directory @@ -128,27 +168,31 @@ def make_temporary_directory(): stat.S_IXOTH) return dirname + def make_temporary_file(): return tempfile.mktemp() + def path_splitter(path): dirname = os.path.dirname(path) basename = os.path.basename(path) return [dirname, basename] + def rspamc(addr, port, filename): mboxgoo = b"From MAILER-DAEMON Fri May 13 19:17:40 2016\r\n" goo = open(filename, 'rb').read() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((addr, port)) s.send(b"CHECK RSPAMC/1.0\r\nContent-length: ") - s.send(str(len(goo+mboxgoo)).encode('utf-8')) + s.send(str(len(goo + mboxgoo)).encode('utf-8')) s.send(b"\r\n\r\n") s.send(mboxgoo) s.send(goo) r = s.recv(2048) return r.decode('utf-8') + def Scan_File(filename, **headers): addr = BuiltIn().get_variable_value("${RSPAMD_LOCAL_ADDR}") port = BuiltIn().get_variable_value("${RSPAMD_PORT_NORMAL}") @@ -162,16 +206,19 @@ def Scan_File(filename, **headers): BuiltIn().set_test_variable("${SCAN_RESULT}", d) return + def Send_SIGUSR1(pid): pid = int(pid) os.kill(pid, signal.SIGUSR1) + def set_directory_ownership(path, username, groupname): if os.getuid() == 0: - uid=pwd.getpwnam(username).pw_uid - gid=grp.getgrnam(groupname).gr_gid + uid = pwd.getpwnam(username).pw_uid + gid = grp.getgrnam(groupname).gr_gid os.chown(path, uid, gid) + def spamc(addr, port, filename): goo = open(filename, 'rb').read() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -184,6 +231,7 @@ def spamc(addr, port, filename): r = s.recv(2048) return r.decode('utf-8') + def TCP_Connect(addr, port): """Attempts to open a TCP connection to specified address:port @@ -191,13 +239,15 @@ def TCP_Connect(addr, port): | Wait Until Keyword Succeeds | 5s | 10ms | TCP Connect | localhost | 8080 | """ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(5) # seconds + s.settimeout(5) # seconds s.connect((addr, port)) s.close() + def ping_rspamd(addr, port): return str(urlopen("http://%s:%s/ping" % (addr, port)).read()) + def redis_check(addr, port): """Attempts to open a TCP connection to specified address:port @@ -205,7 +255,7 @@ def redis_check(addr, port): | Wait Until Keyword Succeeds | 5s | 10ms | TCP Connect | localhost | 8080 | """ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(1.0) # seconds + s.settimeout(1.0) # seconds s.connect((addr, port)) if s.sendall(b"ECHO TEST\n"): result = s.recv(128) @@ -213,6 +263,7 @@ def redis_check(addr, port): else: return False + def update_dictionary(a, b): a.update(b) return a @@ -221,6 +272,7 @@ def update_dictionary(a, b): TERM_TIMEOUT = 10 # wait after sending a SIGTERM signal KILL_WAIT = 20 # additional wait after sending a SIGKILL signal + def shutdown_process(process): # send SIGTERM process.terminate() @@ -229,7 +281,7 @@ def shutdown_process(process): process.wait(TERM_TIMEOUT) return except psutil.TimeoutExpired: - logger.info( "PID {} is not terminated in {} seconds, sending SIGKILL...".format(process.pid, TERM_TIMEOUT)) + logger.info("PID {} is not terminated in {} seconds, sending SIGKILL...".format(process.pid, TERM_TIMEOUT)) try: # send SIGKILL process.kill() @@ -258,6 +310,7 @@ def shutdown_process_with_children(pid): pass psutil.wait_procs(children, timeout=KILL_WAIT) + def write_to_stdin(process_handle, text): if not isinstance(text, bytes): text = bytes(text, 'utf-8') @@ -269,12 +322,14 @@ def write_to_stdin(process_handle, text): out = obj.stdout.read(4096) return out.decode('utf-8') + def get_file_if_exists(file_path): if os.path.exists(file_path): with open(file_path, 'r') as myfile: return myfile.read() return None + def _merge_luacov_stats(statsfile, coverage): """ Reads a coverage stats file written by luacov and merges coverage data to @@ -331,7 +386,7 @@ def collect_lua_coverage(): | Collect Lua Coverage | """ # decided not to do optional coverage so far - #if not 'ENABLE_LUA_COVERAGE' in os.environ['HOME']: + # if not 'ENABLE_LUA_COVERAGE' in os.environ['HOME']: # logger.info("ENABLE_LUA_COVERAGE is not present in env, will not collect Lua coverage") # return -- 2.39.5