parent
76ea3a063f
commit
be18fea136
3 changed files with 131 additions and 37 deletions
|
@ -6,10 +6,14 @@ Test collection management
|
|||
|
||||
from http import HTTPStatus
|
||||
import json
|
||||
import os
|
||||
import pwd
|
||||
import time
|
||||
|
||||
from pytest_cs import wait_for_log, wait_for_http
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
pytestmark = pytest.mark.docker
|
||||
|
||||
|
@ -75,3 +79,59 @@ def test_install_and_disable_collection(crowdsec, flavor):
|
|||
logs = cont.logs().decode().splitlines()
|
||||
# check that there was no attempt to install
|
||||
assert not any(f'Enabled collections : {it}' in line for line in logs)
|
||||
|
||||
|
||||
# already done in bats, prividing here as example of a somewhat complex test
|
||||
def test_taint_bubble_up(crowdsec, tmp_path_factory, flavor):
|
||||
coll = 'crowdsecurity/nginx'
|
||||
env = {
|
||||
'COLLECTIONS': f'{coll}'
|
||||
}
|
||||
|
||||
hub = tmp_path_factory.mktemp("hub")
|
||||
volumes = {
|
||||
hub: {'bind': '/etc/crowdsec/hub', 'mode': 'rw'}
|
||||
}
|
||||
|
||||
with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cont:
|
||||
wait_for_http(cont, 8080, '/health', want_status=HTTPStatus.OK)
|
||||
res = cont.exec_run('cscli collections list -o json')
|
||||
assert res.exit_code == 0
|
||||
j = json.loads(res.output)
|
||||
items = {c['name']: c for c in j['collections']}
|
||||
# implicit check for tainted=False
|
||||
assert items[coll]['status'] == 'enabled'
|
||||
wait_for_log(cont, [
|
||||
f'*Enabled collections : {coll}*',
|
||||
])
|
||||
|
||||
# change file permissions to allow edit
|
||||
current_uid = pwd.getpwuid(os.getuid()).pw_uid
|
||||
res = cont.exec_run(f'chown -R {current_uid} /etc/crowdsec/hub')
|
||||
assert res.exit_code == 0
|
||||
|
||||
scenario = 'crowdsecurity/http-crawl-non_statics'
|
||||
scenario_file = hub / f'scenarios/{scenario}.yaml'
|
||||
|
||||
with open(scenario_file) as f:
|
||||
yml = yaml.safe_load(f)
|
||||
|
||||
yml['description'] += ' (tainted)'
|
||||
# won't be able to read it back because description is taken from the index
|
||||
|
||||
with open(scenario_file, 'w') as f:
|
||||
yaml.dump(yml, f)
|
||||
|
||||
with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cont:
|
||||
wait_for_http(cont, 8080, '/health', want_status=HTTPStatus.OK)
|
||||
res = cont.exec_run(f'cscli scenarios inspect {scenario} -o json')
|
||||
assert res.exit_code == 0
|
||||
j = json.loads(res.output)
|
||||
assert j['tainted'] is True
|
||||
|
||||
res = cont.exec_run('cscli collections list -o json')
|
||||
assert res.exit_code == 0
|
||||
j = json.loads(res.output)
|
||||
items = {c['name']: c for c in j['collections']}
|
||||
assert items['crowdsecurity/nginx']['status'] == 'enabled,tainted'
|
||||
assert items['crowdsecurity/base-http-scenarios']['status'] == 'enabled,tainted'
|
||||
|
|
|
@ -267,6 +267,9 @@ func CollecDepsCheck(v *Item) error {
|
|||
if val.Type == COLLECTIONS {
|
||||
log.Tracef("collec, recurse.")
|
||||
if err := CollecDepsCheck(&val); err != nil {
|
||||
if val.Tainted {
|
||||
v.Tainted = true
|
||||
}
|
||||
return fmt.Errorf("sub collection %s is broken : %s", val.Name, err)
|
||||
}
|
||||
hubIdx[ptrtype][p] = val
|
||||
|
|
|
@ -28,87 +28,118 @@ teardown() {
|
|||
}
|
||||
|
||||
@test "there are 2 collections (linux and sshd)" {
|
||||
run -0 --separate-stderr cscli collections list -o json
|
||||
run -0 jq '.collections | length' <(output)
|
||||
rune -0 cscli collections list -o json
|
||||
rune -0 jq '.collections | length' <(output)
|
||||
assert_output 2
|
||||
}
|
||||
|
||||
@test "can install a collection (as a regular user) and remove it" {
|
||||
# collection is not installed
|
||||
run -0 --separate-stderr cscli collections list -o json
|
||||
run -0 jq -r '.collections[].name' <(output)
|
||||
rune -0 cscli collections list -o json
|
||||
rune -0 jq -r '.collections[].name' <(output)
|
||||
refute_line "crowdsecurity/mysql"
|
||||
|
||||
# we install it
|
||||
run -0 --separate-stderr cscli collections install crowdsecurity/mysql -o human
|
||||
rune -0 cscli collections install crowdsecurity/mysql -o human
|
||||
assert_stderr --partial "Enabled crowdsecurity/mysql"
|
||||
|
||||
# it has been installed
|
||||
run -0 --separate-stderr cscli collections list -o json
|
||||
run -0 jq -r '.collections[].name' <(output)
|
||||
rune -0 cscli collections list -o json
|
||||
rune -0 jq -r '.collections[].name' <(output)
|
||||
assert_line "crowdsecurity/mysql"
|
||||
|
||||
# we install it
|
||||
run -0 cscli collections remove crowdsecurity/mysql -o human
|
||||
assert_output --partial "Removed symlink [crowdsecurity/mysql]"
|
||||
rune -0 cscli collections remove crowdsecurity/mysql -o human
|
||||
assert_stderr --partial "Removed symlink [crowdsecurity/mysql]"
|
||||
|
||||
# it has been removed
|
||||
run -0 --separate-stderr cscli collections list -o json
|
||||
run -0 jq -r '.collections[].name' <(output)
|
||||
rune -0 cscli collections list -o json
|
||||
rune -0 jq -r '.collections[].name' <(output)
|
||||
refute_line "crowdsecurity/mysql"
|
||||
}
|
||||
|
||||
@test "must use --force to remove a collection that belongs to another, which becomes tainted" {
|
||||
# we expect no error since we may have multiple collections, some removed and some not
|
||||
run -0 --separate-stderr cscli collections remove crowdsecurity/sshd
|
||||
rune -0 cscli collections remove crowdsecurity/sshd
|
||||
assert_stderr --partial "crowdsecurity/sshd belongs to other collections"
|
||||
assert_stderr --partial "[crowdsecurity/linux]"
|
||||
|
||||
run -0 --separate-stderr cscli collections remove crowdsecurity/sshd --force
|
||||
rune -0 cscli collections remove crowdsecurity/sshd --force
|
||||
assert_stderr --partial "Removed symlink [crowdsecurity/sshd]"
|
||||
run -0 --separate-stderr cscli collections inspect crowdsecurity/linux -o json
|
||||
run -0 jq -r '.tainted' <(output)
|
||||
rune -0 cscli collections inspect crowdsecurity/linux -o json
|
||||
rune -0 jq -r '.tainted' <(output)
|
||||
assert_output "true"
|
||||
}
|
||||
|
||||
@test "can remove a collection" {
|
||||
run -0 cscli collections remove crowdsecurity/linux
|
||||
assert_output --partial "Removed"
|
||||
assert_output --regexp ".*for the new configuration to be effective."
|
||||
run -0 cscli collections inspect crowdsecurity/linux -o human
|
||||
rune -0 cscli collections remove crowdsecurity/linux
|
||||
assert_stderr --partial "Removed"
|
||||
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||
rune -0 cscli collections inspect crowdsecurity/linux -o human
|
||||
assert_line 'installed: false'
|
||||
}
|
||||
|
||||
@test "collections delete is an alias for collections remove" {
|
||||
run -0 cscli collections delete crowdsecurity/linux
|
||||
assert_output --partial "Removed"
|
||||
assert_output --regexp ".*for the new configuration to be effective."
|
||||
rune -0 cscli collections delete crowdsecurity/linux
|
||||
assert_stderr --partial "Removed"
|
||||
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||
}
|
||||
|
||||
@test "removing a collection that does not exist is noop" {
|
||||
run -0 cscli collections remove crowdsecurity/apache2
|
||||
refute_output --partial "Removed"
|
||||
assert_output --regexp ".*for the new configuration to be effective."
|
||||
rune -0 cscli collections remove crowdsecurity/apache2
|
||||
refute_stderr --partial "Removed"
|
||||
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||
}
|
||||
|
||||
@test "can remove a removed collection" {
|
||||
run -0 cscli collections install crowdsecurity/mysql
|
||||
run -0 cscli collections remove crowdsecurity/mysql
|
||||
assert_output --partial "Removed"
|
||||
run -0 cscli collections remove crowdsecurity/mysql
|
||||
refute_output --partial "Removed"
|
||||
rune -0 cscli collections install crowdsecurity/mysql
|
||||
rune -0 cscli collections remove crowdsecurity/mysql
|
||||
assert_stderr --partial "Removed"
|
||||
rune -0 cscli collections remove crowdsecurity/mysql
|
||||
refute_stderr --partial "Removed"
|
||||
}
|
||||
|
||||
@test "can remove all collections" {
|
||||
# we may have this too, from package installs
|
||||
run cscli parsers delete crowdsecurity/whitelists
|
||||
run -0 cscli collections remove --all
|
||||
assert_output --partial "Removed symlink [crowdsecurity/sshd]"
|
||||
assert_output --partial "Removed symlink [crowdsecurity/linux]"
|
||||
run -0 --separate-stderr cscli hub list -o json
|
||||
rune cscli parsers delete crowdsecurity/whitelists
|
||||
rune -0 cscli collections remove --all
|
||||
assert_stderr --partial "Removed symlink [crowdsecurity/sshd]"
|
||||
assert_stderr --partial "Removed symlink [crowdsecurity/linux]"
|
||||
rune -0 --separate-stderr cscli hub list -o json
|
||||
assert_json '{collections:[],parsers:[],postoverflows:[],scenarios:[]}'
|
||||
run -0 cscli collections remove --all
|
||||
assert_output --partial 'Disabled 0 items'
|
||||
rune -0 cscli collections remove --all
|
||||
assert_stderr --partial 'Disabled 0 items'
|
||||
}
|
||||
|
||||
@test "a taint bubbles up to the top collection" {
|
||||
coll=crowdsecurity/nginx
|
||||
subcoll=crowdsecurity/base-http-scenarios
|
||||
scenario=crowdsecurity/http-crawl-non_statics
|
||||
|
||||
# install a collection with dependencies
|
||||
rune -0 cscli collections install "$coll"
|
||||
|
||||
# the collection, subcollection and scenario are installed and not tainted
|
||||
# we have to default to false because tainted is (as of 1.4.6) returned
|
||||
# only when true
|
||||
rune -0 cscli collections inspect "$coll" -o json
|
||||
rune -0 jq -e '(.installed,.tainted|false)==(true,false)' <(output)
|
||||
rune -0 cscli collections inspect "$subcoll" -o json
|
||||
rune -0 jq -e '(.installed,.tainted|false)==(true,false)' <(output)
|
||||
rune -0 cscli scenarios inspect "$scenario" -o json
|
||||
rune -0 jq -e '(.installed,.tainted|false)==(true,false)' <(output)
|
||||
|
||||
# we taint the scenario
|
||||
HUB_DIR=$(config_get '.config_paths.hub_dir')
|
||||
yq e '.description="I am tainted"' -i "$HUB_DIR/scenarios/$scenario.yaml"
|
||||
|
||||
# the collection, subcollection and scenario are now tainted
|
||||
rune -0 cscli scenarios inspect "$scenario" -o json
|
||||
rune -0 jq -e '(.installed,.tainted)==(true,true)' <(output)
|
||||
rune -0 cscli collections inspect "$subcoll" -o json
|
||||
rune -0 jq -e '(.installed,.tainted)==(true,true)' <(output)
|
||||
rune -0 cscli collections inspect "$coll" -o json
|
||||
rune -0 jq -e '(.installed,.tainted)==(true,true)' <(output)
|
||||
}
|
||||
|
||||
# TODO test download-only
|
||||
|
|
Loading…
Reference in a new issue