parent
76ea3a063f
commit
be18fea136
|
@ -6,10 +6,14 @@ Test collection management
|
||||||
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import time
|
||||||
|
|
||||||
from pytest_cs import wait_for_log, wait_for_http
|
from pytest_cs import wait_for_log, wait_for_http
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
pytestmark = pytest.mark.docker
|
pytestmark = pytest.mark.docker
|
||||||
|
|
||||||
|
@ -75,3 +79,59 @@ def test_install_and_disable_collection(crowdsec, flavor):
|
||||||
logs = cont.logs().decode().splitlines()
|
logs = cont.logs().decode().splitlines()
|
||||||
# check that there was no attempt to install
|
# check that there was no attempt to install
|
||||||
assert not any(f'Enabled collections : {it}' in line for line in logs)
|
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 {
|
if val.Type == COLLECTIONS {
|
||||||
log.Tracef("collec, recurse.")
|
log.Tracef("collec, recurse.")
|
||||||
if err := CollecDepsCheck(&val); err != nil {
|
if err := CollecDepsCheck(&val); err != nil {
|
||||||
|
if val.Tainted {
|
||||||
|
v.Tainted = true
|
||||||
|
}
|
||||||
return fmt.Errorf("sub collection %s is broken : %s", val.Name, err)
|
return fmt.Errorf("sub collection %s is broken : %s", val.Name, err)
|
||||||
}
|
}
|
||||||
hubIdx[ptrtype][p] = val
|
hubIdx[ptrtype][p] = val
|
||||||
|
|
|
@ -28,87 +28,118 @@ teardown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "there are 2 collections (linux and sshd)" {
|
@test "there are 2 collections (linux and sshd)" {
|
||||||
run -0 --separate-stderr cscli collections list -o json
|
rune -0 cscli collections list -o json
|
||||||
run -0 jq '.collections | length' <(output)
|
rune -0 jq '.collections | length' <(output)
|
||||||
assert_output 2
|
assert_output 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "can install a collection (as a regular user) and remove it" {
|
@test "can install a collection (as a regular user) and remove it" {
|
||||||
# collection is not installed
|
# collection is not installed
|
||||||
run -0 --separate-stderr cscli collections list -o json
|
rune -0 cscli collections list -o json
|
||||||
run -0 jq -r '.collections[].name' <(output)
|
rune -0 jq -r '.collections[].name' <(output)
|
||||||
refute_line "crowdsecurity/mysql"
|
refute_line "crowdsecurity/mysql"
|
||||||
|
|
||||||
# we install it
|
# 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"
|
assert_stderr --partial "Enabled crowdsecurity/mysql"
|
||||||
|
|
||||||
# it has been installed
|
# it has been installed
|
||||||
run -0 --separate-stderr cscli collections list -o json
|
rune -0 cscli collections list -o json
|
||||||
run -0 jq -r '.collections[].name' <(output)
|
rune -0 jq -r '.collections[].name' <(output)
|
||||||
assert_line "crowdsecurity/mysql"
|
assert_line "crowdsecurity/mysql"
|
||||||
|
|
||||||
# we install it
|
# we install it
|
||||||
run -0 cscli collections remove crowdsecurity/mysql -o human
|
rune -0 cscli collections remove crowdsecurity/mysql -o human
|
||||||
assert_output --partial "Removed symlink [crowdsecurity/mysql]"
|
assert_stderr --partial "Removed symlink [crowdsecurity/mysql]"
|
||||||
|
|
||||||
# it has been removed
|
# it has been removed
|
||||||
run -0 --separate-stderr cscli collections list -o json
|
rune -0 cscli collections list -o json
|
||||||
run -0 jq -r '.collections[].name' <(output)
|
rune -0 jq -r '.collections[].name' <(output)
|
||||||
refute_line "crowdsecurity/mysql"
|
refute_line "crowdsecurity/mysql"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "must use --force to remove a collection that belongs to another, which becomes tainted" {
|
@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
|
# 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/sshd belongs to other collections"
|
||||||
assert_stderr --partial "[crowdsecurity/linux]"
|
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]"
|
assert_stderr --partial "Removed symlink [crowdsecurity/sshd]"
|
||||||
run -0 --separate-stderr cscli collections inspect crowdsecurity/linux -o json
|
rune -0 cscli collections inspect crowdsecurity/linux -o json
|
||||||
run -0 jq -r '.tainted' <(output)
|
rune -0 jq -r '.tainted' <(output)
|
||||||
assert_output "true"
|
assert_output "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "can remove a collection" {
|
@test "can remove a collection" {
|
||||||
run -0 cscli collections remove crowdsecurity/linux
|
rune -0 cscli collections remove crowdsecurity/linux
|
||||||
assert_output --partial "Removed"
|
assert_stderr --partial "Removed"
|
||||||
assert_output --regexp ".*for the new configuration to be effective."
|
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||||
run -0 cscli collections inspect crowdsecurity/linux -o human
|
rune -0 cscli collections inspect crowdsecurity/linux -o human
|
||||||
assert_line 'installed: false'
|
assert_line 'installed: false'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "collections delete is an alias for collections remove" {
|
@test "collections delete is an alias for collections remove" {
|
||||||
run -0 cscli collections delete crowdsecurity/linux
|
rune -0 cscli collections delete crowdsecurity/linux
|
||||||
assert_output --partial "Removed"
|
assert_stderr --partial "Removed"
|
||||||
assert_output --regexp ".*for the new configuration to be effective."
|
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "removing a collection that does not exist is noop" {
|
@test "removing a collection that does not exist is noop" {
|
||||||
run -0 cscli collections remove crowdsecurity/apache2
|
rune -0 cscli collections remove crowdsecurity/apache2
|
||||||
refute_output --partial "Removed"
|
refute_stderr --partial "Removed"
|
||||||
assert_output --regexp ".*for the new configuration to be effective."
|
assert_stderr --regexp ".*for the new configuration to be effective."
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "can remove a removed collection" {
|
@test "can remove a removed collection" {
|
||||||
run -0 cscli collections install crowdsecurity/mysql
|
rune -0 cscli collections install crowdsecurity/mysql
|
||||||
run -0 cscli collections remove crowdsecurity/mysql
|
rune -0 cscli collections remove crowdsecurity/mysql
|
||||||
assert_output --partial "Removed"
|
assert_stderr --partial "Removed"
|
||||||
run -0 cscli collections remove crowdsecurity/mysql
|
rune -0 cscli collections remove crowdsecurity/mysql
|
||||||
refute_output --partial "Removed"
|
refute_stderr --partial "Removed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "can remove all collections" {
|
@test "can remove all collections" {
|
||||||
# we may have this too, from package installs
|
# we may have this too, from package installs
|
||||||
run cscli parsers delete crowdsecurity/whitelists
|
rune cscli parsers delete crowdsecurity/whitelists
|
||||||
run -0 cscli collections remove --all
|
rune -0 cscli collections remove --all
|
||||||
assert_output --partial "Removed symlink [crowdsecurity/sshd]"
|
assert_stderr --partial "Removed symlink [crowdsecurity/sshd]"
|
||||||
assert_output --partial "Removed symlink [crowdsecurity/linux]"
|
assert_stderr --partial "Removed symlink [crowdsecurity/linux]"
|
||||||
run -0 --separate-stderr cscli hub list -o json
|
rune -0 --separate-stderr cscli hub list -o json
|
||||||
assert_json '{collections:[],parsers:[],postoverflows:[],scenarios:[]}'
|
assert_json '{collections:[],parsers:[],postoverflows:[],scenarios:[]}'
|
||||||
run -0 cscli collections remove --all
|
rune -0 cscli collections remove --all
|
||||||
assert_output --partial 'Disabled 0 items'
|
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
|
# TODO test download-only
|
||||||
|
|
Loading…
Reference in a new issue