Skip to content

Commit e3722a0

Browse files
committed
Utility to run the entire toolchain
Signed-off-by: Sebitosh <[email protected]>
1 parent 71c3f99 commit e3722a0

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,46 @@ SecAction "id:100020,phase:2 pass, setenv:'after=789'"
697697
```
698698

699699
## Run the tool
700+
### Run the entire toolchain
701+
702+
#### Required:
703+
* [albedo](https://github.com/coreruleset/albedo)
704+
* [go-ftw](https://github.com/coreruleset/go-ftw)
705+
* apache2 with the modsecurity and proxy modules for using the `apache2_ubuntu` + ModSecurity V2 infrastructure
706+
707+
To run the tests on a provided configuration, run the tool:
708+
709+
~~~bash
710+
$ ./mrts/mrts.py
711+
usage: mrts.py [-h] -i /path/to/infra/ -r /path/to/mrts/*.yaml -e /path/to/mrts/rules/ -t /path/to/mrts/tests/ [-c]
712+
[-f /path/to/mrts/ftw.mrts.config.yaml] [-v]
713+
mrts.py: error: the following arguments are required: -i/--infrastructure, -r/--rulesdef, -e/--expdir, -t/--testdir
714+
~~~
715+
716+
As you can see there are few command line arguments.
717+
* `-i` - WAF infrastructure files
718+
* `-r` - rules definition files
719+
* `-e` - export directory where rules will be written
720+
* `-t` - export test directory where tests will be written
721+
* `-c` - clean previously generated rule and test files
722+
* `-f` - `go-ftw` custom configuration file, if you don't want to use the default file provided in the infrastructure directory
723+
* `-v` - verbose output
724+
725+
For running without a custom `go-ftw` configuration, run the `mrts.py` script from the root directory of the project (or else provide a ftw configuration file with a correct relative path).
726+
727+
~~~bash
728+
$ ./mrts/mrts.py -i config_infra/apache2_ubuntu/ -r config_tests/ -e generated/rules/ -t generated/tests/regression/tests/
729+
Generate rules and tests
730+
Launch backend
731+
Launch infrastructure
732+
Executing test set...
733+
🎉🎉🎉 Success: test set passed
734+
Backend shutdown
735+
Infrastructure shutdown
736+
MRTS completed
737+
~~~
738+
739+
### Rule and test generation
700740

701741
To generate the rules and their tests, run the tool:
702742

mrts.load

Lines changed: 0 additions & 2 deletions
This file was deleted.

mrts/mrts.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import glob
5+
import runpy
6+
import shutil
7+
import subprocess
8+
import sys
9+
import os
10+
11+
12+
def clean_generated_directories(genrules, gentests, verbose):
13+
old_rules = glob.glob(os.path.join(genrules, "*.conf"))
14+
old_test = glob.glob(os.path.join(gentests, "*.yaml"))
15+
for rule in old_rules:
16+
os.remove(rule)
17+
for test in old_test:
18+
os.remove(test)
19+
if verbose:
20+
print("Cleaned generated directories")
21+
22+
23+
def generate_rules(testconfig, genrules, gentests, verbose):
24+
testconfig = os.path.join(testconfig, "*.yaml")
25+
26+
current_dir = os.path.dirname(os.path.abspath(__file__))
27+
generate_rules_script = os.path.join(current_dir, "generate-rules.py")
28+
29+
genrule_stdout = sys.stdout if verbose else subprocess.DEVNULL
30+
subprocess.run([generate_rules_script, "-r", *glob.glob(testconfig), "-e",genrules, "-t", gentests],
31+
stdout=genrule_stdout)
32+
33+
34+
def launch_albedo():
35+
if not shutil.which("albedo"):
36+
print("Failure: albedo not installed or found in system PATH")
37+
sys.exit(1)
38+
39+
return subprocess.Popen(
40+
["albedo", "-b", "127.0.0.1", "-p", "8000"],
41+
stdout=subprocess.DEVNULL,
42+
stderr=subprocess.DEVNULL)
43+
44+
45+
def execute_test_set(ftwconfig, infra, gentests, verbose):
46+
if not shutil.which("go-ftw"):
47+
print("Failure: go-ftw not installed or found in system PATH")
48+
sys.exit(1)
49+
50+
if ftwconfig is None:
51+
ftwconfig = os.path.join(infra, "ftw.mrts.config.yaml")
52+
53+
go_ftw = subprocess.Popen(
54+
["go-ftw", "run", "--config", ftwconfig, "--dir", gentests, "--wait-for-expect-status-code", "200", "--fail-fast"],
55+
stdout=subprocess.PIPE
56+
)
57+
stdout = ""
58+
for line in go_ftw.stdout:
59+
stdout += line.decode("utf-8")
60+
if verbose:
61+
print(line.decode("utf-8"), end="")
62+
63+
if '💥' in stdout:
64+
print("💥💥💥 Failure: test set failed")
65+
elif '🎉' in stdout:
66+
print("🎉🎉🎉 Success: test set passed")
67+
else:
68+
print("Failure: Incorrect go-ftw output")
69+
70+
71+
def write_mrts_load(infra_path, genrules_path, verbose):
72+
load_file_path = os.path.join(infra_path, "mrts.load")
73+
with open(load_file_path, "w") as f:
74+
f.write(f"Include {genrules_path}\n")
75+
76+
if verbose:
77+
print(f"File '{load_file_path}' created successfully with content: Include {genrules_path}")
78+
79+
80+
def delete_mrts_load(infra_path, verbose):
81+
file_path = os.path.join(infra_path, "mrts.load")
82+
if os.path.exists(file_path):
83+
os.remove(file_path)
84+
if verbose:
85+
print(f"File '{file_path}' has been deleted.")
86+
else:
87+
if verbose:
88+
print(f"File '{file_path}' does not exist.")
89+
90+
91+
def main(infra, ftwconfig, testconfig, genrules, gentests, verbose, clean):
92+
93+
if not os.getcwd() == os.path.dirname(os.path.dirname(os.path.abspath(__file__))):
94+
print("This script can only run from the MRTS root directory")
95+
sys.exit(1)
96+
97+
# Optionally, remove previous .conf and .yaml generated
98+
if clean:
99+
clean_generated_directories(genrules, gentests, verbose)
100+
101+
# Step 1: generate rules and tests
102+
print("Generate rules and tests")
103+
generate_rules(testconfig, genrules, gentests, verbose)
104+
105+
# Step 2: start backend
106+
print("Launch backend")
107+
backend = launch_albedo()
108+
109+
# Step 3: create temporary file in infra to include rules, figuring out the absolute path dynamically
110+
infra_path = os.path.join(infra, "infra")
111+
genrules_abs_path = os.path.join(os.path.abspath(genrules), "*.conf")
112+
write_mrts_load(infra_path, genrules_abs_path, verbose)
113+
114+
# Step 4: launch infrastructure from start script
115+
print("Launch infrastructure")
116+
runpy.run_path(os.path.join(infra, "start.py"))
117+
118+
# Step 5: use go-ftw to run tests
119+
print("Executing test set...")
120+
execute_test_set(ftwconfig, infra, gentests, verbose)
121+
122+
# Step 6: shutdown backend
123+
backend.terminate()
124+
print("Backend shutdown")
125+
126+
# Step 7: remove temporary file including rules
127+
delete_mrts_load(infra_path, verbose)
128+
129+
# Step 8: shutdown infrastructure from stop script
130+
runpy.run_path(os.path.join(infra, "stop.py"))
131+
print("Infrastructure shutdown")
132+
133+
# The end
134+
print("MRTS completed")
135+
136+
137+
if __name__ == '__main__':
138+
parser = argparse.ArgumentParser(description="MRTS global utility")
139+
parser.add_argument("-i", "--infrastructure", metavar='/path/to/infra/', type=str,
140+
help='Directory path to infrastructure to be tested', required=True)
141+
parser.add_argument("-r", "--rulesdef", metavar='/path/to/mrts/*.yaml', type=str,
142+
help='Directory path to MRTS rules definition', required=True)
143+
parser.add_argument("-e", "--expdir", metavar='/path/to/mrts/rules/', type=str,
144+
help='Directory path to generated MRTS rules', required=True)
145+
parser.add_argument("-t", "--testdir", metavar='/path/to/mrts/tests/', type=str,
146+
help='Directory path to generated MRTS tests', required=True)
147+
parser.add_argument("-c", "--clean", action='store_true',
148+
help='Clean generated rules and tests directories before new rule generation',
149+
required=False, default=False)
150+
parser.add_argument("-f", "--ftwconfig", metavar='/path/to/mrts/ftw.mrts.config.yaml', type=str,
151+
help='go-ftw config file', required=False, default=None)
152+
parser.add_argument("-v", "--verbose", action='store_true',
153+
help='Verbose output', required=False, default=False)
154+
155+
args = parser.parse_args()
156+
157+
main(args.infrastructure, args.ftwconfig, args.rulesdef, args.expdir, args.testdir, args.verbose, args.clean)
158+

0 commit comments

Comments
 (0)