diff --git a/.github/workflows/ci_functests-install.yml b/.github/workflows/ci_functests-install.yml index 066ac595b..6727b9578 100644 --- a/.github/workflows/ci_functests-install.yml +++ b/.github/workflows/ci_functests-install.yml @@ -72,6 +72,10 @@ jobs: run: | cd scripts/func_tests/ ./tests_post-install_5simulation.sh + - name: "Test post-install plugins" + run: | + cd scripts/func_tests/ + sudo ./tests_post-install_7_plugin.sh - name: "Uninstall" run: sudo ./wizard.sh --uninstall - name: "Test post remove" diff --git a/scripts/func_tests/config/config.yaml b/scripts/func_tests/config/config.yaml index db955b1ae..873fe2bbb 100644 --- a/scripts/func_tests/config/config.yaml +++ b/scripts/func_tests/config/config.yaml @@ -11,11 +11,16 @@ config_paths: simulation_path: /etc/crowdsec/simulation.yaml hub_dir: /etc/crowdsec/hub/ index_path: /etc/crowdsec/hub/.index.json + notification_dir: /etc/crowdsec/notifications/ + plugin_dir: /usr/local/lib/crowdsec/plugins crowdsec_service: acquisition_path: /etc/crowdsec/acquis.yaml parser_routines: 1 cscli: output: human +plugin_config: + user: nobody # plugin process would be ran on behalf of this user + group: nogroup # plugin process would be ran on behalf of this group db_config: log_level: info type: sqlite diff --git a/scripts/func_tests/config/config_no_agent.yaml b/scripts/func_tests/config/config_no_agent.yaml index 634d459da..e524835ab 100644 --- a/scripts/func_tests/config/config_no_agent.yaml +++ b/scripts/func_tests/config/config_no_agent.yaml @@ -12,6 +12,8 @@ config_paths: simulation_path: /etc/crowdsec/simulation.yaml hub_dir: /etc/crowdsec/hub/ index_path: /etc/crowdsec/hub/.index.json + notification_dir: /etc/crowdsec/notifications/ + plugin_dir: /usr/local/lib/crowdsec/plugins cscli: output: human db_config: @@ -21,6 +23,9 @@ db_config: flush: max_items: 5000 max_age: 7d +plugin_config: + user: nobody # plugin process would be ran on behalf of this user + group: nogroup # plugin process would be ran on behalf of this group api: client: insecure_skip_verify: false diff --git a/scripts/func_tests/config/config_no_capi.yaml b/scripts/func_tests/config/config_no_capi.yaml index 548abc933..f7904ba81 100644 --- a/scripts/func_tests/config/config_no_capi.yaml +++ b/scripts/func_tests/config/config_no_capi.yaml @@ -11,6 +11,8 @@ config_paths: simulation_path: /etc/crowdsec/simulation.yaml hub_dir: /etc/crowdsec/hub/ index_path: /etc/crowdsec/hub/.index.json + notification_dir: /etc/crowdsec/notifications/ + plugin_dir: /usr/local/lib/crowdsec/plugins crowdsec_service: acquisition_path: /etc/crowdsec/acquis.yaml parser_routines: 1 @@ -23,6 +25,9 @@ db_config: flush: max_items: 5000 max_age: 7d +plugin_config: + user: nobody # plugin process would be ran on behalf of this user + group: nogroup # plugin process would be ran on behalf of this group api: client: insecure_skip_verify: false diff --git a/scripts/func_tests/config/config_no_lapi.yaml b/scripts/func_tests/config/config_no_lapi.yaml index 73b1d7dad..e729f828e 100644 --- a/scripts/func_tests/config/config_no_lapi.yaml +++ b/scripts/func_tests/config/config_no_lapi.yaml @@ -11,11 +11,16 @@ config_paths: simulation_path: /etc/crowdsec/simulation.yaml hub_dir: /etc/crowdsec/hub/ index_path: /etc/crowdsec/hub/.index.json + notification_dir: /etc/crowdsec/notifications/ + plugin_dir: /usr/local/lib/crowdsec/plugins crowdsec_service: acquisition_path: /etc/crowdsec/acquis.yaml parser_routines: 1 cscli: output: human +plugin_config: + user: nobody # plugin process would be ran on behalf of this user + group: nogroup # plugin process would be ran on behalf of this group db_config: log_level: info type: sqlite diff --git a/scripts/func_tests/config/http.yaml b/scripts/func_tests/config/http.yaml new file mode 100644 index 000000000..c7f7b2572 --- /dev/null +++ b/scripts/func_tests/config/http.yaml @@ -0,0 +1,25 @@ +# Don't change this +type: http + +name: http_default # this must match with the registered plugin in the profile +log_level: info # Options include: trace, debug, info, warn, error, off + +format: | # This template receives list of models.Alert objects. The request body would contain this. + {{.|toJson}} + +url: http://localhost:9999 # plugin will make requests to this url. Eg value https://www.example.com/ + +method: POST # eg either of "POST", "GET", "PUT" and other http verbs is valid value. + +# headers: +# Authorization: token 0x64312313 + +# skip_tls_verification: # either true or false. Default is false + +# group_wait: # duration to wait collecting alerts before sending to this plugin, eg "30s" + +group_threshold: 2 # if alerts exceed this, then the plugin will be sent the message. eg "10" + +# max_retry: # number of tries to attempt to send message to plugins in case of error. + +# timeout: # duration to wait for response from plugin before considering this attempt a failure. eg "10s" diff --git a/scripts/func_tests/config/profiles.yaml b/scripts/func_tests/config/profiles.yaml new file mode 100644 index 000000000..be66b1f83 --- /dev/null +++ b/scripts/func_tests/config/profiles.yaml @@ -0,0 +1,12 @@ +name: default_ip_remediation +#debug: true +filters: + - 1==1 +decisions: + - type: ban + duration: 4h +notifications: +# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. +# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. + - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. +on_success: break diff --git a/scripts/func_tests/mock_http_server.py b/scripts/func_tests/mock_http_server.py new file mode 100644 index 000000000..319631bd2 --- /dev/null +++ b/scripts/func_tests/mock_http_server.py @@ -0,0 +1,26 @@ +import json +from http.server import HTTPServer, BaseHTTPRequestHandler + +class RequestHandler(BaseHTTPRequestHandler): + def do_POST(self): + request_path = self.path + request_body = self.rfile.read(int(self.headers['Content-Length'])) + request_body = json.loads(request_body) + log = { + "path": request_path, + "status": 200, + "request_body": request_body, + } + print(json.dumps(log)) + self.send_response(200) + self.send_header('Content-type','application/json') + self.end_headers() + self.wfile.write(json.dumps({}).encode()) + return + + def log_message(self, format, *args): + return + +if __name__ == "__main__" : + server = HTTPServer(('', 9999), RequestHandler) + server.serve_forever() \ No newline at end of file diff --git a/scripts/func_tests/tests_post-install_7_plugin.sh b/scripts/func_tests/tests_post-install_7_plugin.sh new file mode 100755 index 000000000..8719f9b8a --- /dev/null +++ b/scripts/func_tests/tests_post-install_7_plugin.sh @@ -0,0 +1,81 @@ +#! /usr/bin/env bash +# -*- coding: utf-8 -*- + +source tests_base.sh + +MOCK_SERVER_PID="" + +function backup () { + cat /etc/crowdsec/profiles.yaml > ./backup_profiles.yaml + cat /etc/crowdsec/notifications/http.yaml > ./backup_http.yaml +} + +function restore_backup () { + cat ./backup_profiles.yaml > /etc/crowdsec/profiles.yaml + cat ./backup_http.yaml > /etc/crowdsec/notifications/http.yaml +} + +function clear_backup() { + rm ./backup_profiles.yaml + rm ./backup_http.yaml +} + +function modify_config() { + cp ./config/http.yaml /etc/crowdsec/notifications/http.yaml + cp ./config/profiles.yaml /etc/crowdsec/profiles.yaml + systemctl restart crowdsec +} + +function setup_tests() { + backup + cscli decisions delete --all + modify_config + python3 -u mock_http_server.py > mock_http_server_logs.log & + MOCK_SERVER_PID=$! +} + +function cleanup_tests() { + restore_backup + clear_backup + kill -9 $MOCK_SERVER_PID + rm mock_http_server_logs.log + systemctl restart crowdsec +} + +function run_tests() { + log_line_count=$(cat mock_http_server_logs.log | wc -l) + if [[ $log_line_count -ne "0" ]] ; then + cleanup_tests + fail "expected 0 log lines fom mock http server before adding decisions" + fi + cscli decisions add --ip 1.2.3.4 --duration 30s + cscli decisions add --ip 1.2.3.5 --duration 30s + sleep 5 + log_line_count=$(cat mock_http_server_logs.log | wc -l) + if [[ $log_line_count -ne "1" ]] ; then + cleanup_tests + fail "expected 1 log line from http server" + fi + + total_alerts=$(cat mock_http_server_logs.log | jq .request_body | jq length) + if [[ $total_alerts -ne "2" ]] ; then + cleanup_tests + fail "expected to receive 2 alerts in the request body from plugin" + fi + + first_received_ip=$(cat mock_http_server_logs.log | jq -r .request_body[0].decisions[0].value) + if [[ $first_received_ip != "1.2.3.4" ]] ; then + cleanup_tests + fail "expected to receive IP 1.2.3.4 as value of first decision" + fi + + second_received_ip=$(cat mock_http_server_logs.log | jq -r .request_body[1].decisions[0].value) + if [[ $second_received_ip != "1.2.3.5" ]] ; then + cleanup_tests + fail "expected to receive IP 1.2.3.5 as value of second decision" + fi +} + +setup_tests +run_tests +cleanup_tests \ No newline at end of file