github.com/crowdsecurity/crowdsec@v1.6.1/test/bats/01_cscli.bats (about) 1 #!/usr/bin/env bats 2 # vim: ft=bats:list:ts=8:sts=4:sw=4:et:ai:si: 3 4 set -u 5 6 setup_file() { 7 load "../lib/setup_file.sh" 8 } 9 10 teardown_file() { 11 load "../lib/teardown_file.sh" 12 } 13 14 setup() { 15 load "../lib/setup.sh" 16 load "../lib/bats-file/load.bash" 17 ./instance-data load 18 # don't run crowdsec here, not all tests require a running instance 19 } 20 21 teardown() { 22 cd "$TEST_DIR" || exit 1 23 ./instance-crowdsec stop 24 } 25 26 #---------- 27 28 @test "cscli - usage" { 29 rune -0 cscli 30 assert_output --partial "Usage:" 31 assert_output --partial "cscli [command]" 32 assert_output --partial "Available Commands:" 33 34 # no "usage" output after every error 35 rune -1 cscli blahblah 36 # error is displayed as log entry, not with print 37 assert_stderr --partial 'level=fatal msg="unknown command \"blahblah\" for \"cscli\""' 38 refute_stderr --partial 'unknown command "blahblah" for "cscli"' 39 } 40 41 @test "cscli version" { 42 rune -0 cscli version 43 assert_stderr --partial "version:" 44 assert_stderr --partial "Codename:" 45 assert_stderr --partial "BuildDate:" 46 assert_stderr --partial "GoVersion:" 47 assert_stderr --partial "Platform:" 48 assert_stderr --partial "Constraint_parser:" 49 assert_stderr --partial "Constraint_scenario:" 50 assert_stderr --partial "Constraint_api:" 51 assert_stderr --partial "Constraint_acquis:" 52 53 # should work without configuration file 54 rm "${CONFIG_YAML}" 55 rune -0 cscli version 56 assert_stderr --partial "version:" 57 } 58 59 @test "cscli help" { 60 rune -0 cscli help 61 assert_line "Available Commands:" 62 assert_line --regexp ".* help .* Help about any command" 63 64 # should work without configuration file 65 rm "${CONFIG_YAML}" 66 rune -0 cscli help 67 assert_line "Available Commands:" 68 } 69 70 @test "cscli config show" { 71 rune -0 cscli config show -o human 72 assert_output --partial "Global:" 73 assert_output --partial "Crowdsec:" 74 assert_output --partial "cscli:" 75 assert_output --partial "Local API Server:" 76 77 rune -0 cscli config show -o json 78 assert_output --partial '"API":' 79 assert_output --partial '"Common":' 80 assert_output --partial '"ConfigPaths":' 81 assert_output --partial '"Crowdsec":' 82 assert_output --partial '"Cscli":' 83 assert_output --partial '"DbConfig":' 84 assert_output --partial '"Hub":' 85 assert_output --partial '"PluginConfig":' 86 assert_output --partial '"Prometheus":' 87 88 rune -0 cscli config show -o raw 89 assert_line "api:" 90 assert_line "common:" 91 assert_line "config_paths:" 92 assert_line "crowdsec_service:" 93 assert_line "cscli:" 94 assert_line "db_config:" 95 assert_line "plugin_config:" 96 assert_line "prometheus:" 97 98 rune -0 cscli config show --key Config.API.Server.ListenURI 99 assert_output "127.0.0.1:8080" 100 101 # check that LAPI configuration is loaded (human and json, not shows in raw) 102 103 sock=$(config_get '.api.server.listen_socket') 104 105 rune -0 cscli config show -o human 106 assert_line --regexp ".*- URL +: http://127.0.0.1:8080/" 107 assert_line --regexp ".*- Login +: githubciXXXXXXXXXXXXXXXXXXXXXXXX([a-zA-Z0-9]{16})?" 108 assert_line --regexp ".*- Credentials File +: .*/local_api_credentials.yaml" 109 assert_line --regexp ".*- Listen URL +: 127.0.0.1:8080" 110 assert_line --regexp ".*- Listen Socket +: $sock" 111 112 rune -0 cscli config show -o json 113 rune -0 jq -c '.API.Client.Credentials | [.url,.login[0:32]]' <(output) 114 assert_json '["http://127.0.0.1:8080/","githubciXXXXXXXXXXXXXXXXXXXXXXXX"]' 115 116 # pointer to boolean 117 118 rune -0 cscli config show --key Config.API.Client.InsecureSkipVerify 119 assert_output "&false" 120 121 # complex type 122 rune -0 cscli config show --key Config.Prometheus 123 assert_output - <<-EOT 124 &csconfig.PrometheusCfg{ 125 Enabled: true, 126 Level: "full", 127 ListenAddr: "127.0.0.1", 128 ListenPort: 6060, 129 } 130 EOT 131 } 132 133 134 @test "cscli - required configuration paths" { 135 config=$(cat "${CONFIG_YAML}") 136 configdir=$(config_get '.config_paths.config_dir') 137 138 # required configuration paths with no defaults 139 140 config_set 'del(.config_paths)' 141 rune -1 cscli hub list 142 assert_stderr --partial 'no configuration paths provided' 143 echo "$config" > "${CONFIG_YAML}" 144 145 config_set 'del(.config_paths.data_dir)' 146 rune -1 cscli hub list 147 assert_stderr --partial "please provide a data directory with the 'data_dir' directive in the 'config_paths' section" 148 echo "$config" > "${CONFIG_YAML}" 149 150 # defaults 151 152 config_set 'del(.config_paths.hub_dir)' 153 rune -0 cscli hub list 154 rune -0 cscli config show --key Config.ConfigPaths.HubDir 155 assert_output "$configdir/hub" 156 echo "$config" > "${CONFIG_YAML}" 157 158 config_set 'del(.config_paths.index_path)' 159 rune -0 cscli hub list 160 rune -0 cscli config show --key Config.ConfigPaths.HubIndexFile 161 assert_output "$configdir/hub/.index.json" 162 echo "$config" > "${CONFIG_YAML}" 163 } 164 165 @test "cscli config show-yaml" { 166 rune -0 cscli config show-yaml 167 rune -0 yq .common.log_level <(output) 168 assert_output "info" 169 echo 'common: {"log_level": "debug"}' >> "${CONFIG_YAML}.local" 170 rune -0 cscli config show-yaml 171 rune -0 yq .common.log_level <(output) 172 assert_output "debug" 173 } 174 175 @test "cscli config backup / restore" { 176 # test that we need a valid path 177 # disabled because in CI, the empty string is not passed as a parameter 178 #rune -1 cscli config backup "" 179 #assert_stderr --partial "failed to backup config: directory path can't be empty" 180 181 rune -1 cscli config backup "/dev/null/blah" 182 assert_stderr --partial "failed to backup config: while creating /dev/null/blah: mkdir /dev/null/blah: not a directory" 183 184 # pick a dirpath 185 backupdir=$(TMPDIR="${BATS_TEST_TMPDIR}" mktemp -u) 186 187 # succeed the first time 188 rune -0 cscli config backup "${backupdir}" 189 assert_stderr --partial "Starting configuration backup" 190 191 # don't overwrite an existing backup 192 rune -1 cscli config backup "${backupdir}" 193 assert_stderr --partial "failed to backup config" 194 assert_stderr --partial "file exists" 195 196 SIMULATION_YAML="$(config_get '.config_paths.simulation_path')" 197 198 # restore 199 rm "${SIMULATION_YAML}" 200 rune -0 cscli config restore "${backupdir}" 201 assert_file_exists "${SIMULATION_YAML}" 202 203 # cleanup 204 rm -rf -- "${backupdir:?}" 205 206 # backup: detect missing files 207 rm "${SIMULATION_YAML}" 208 rune -1 cscli config backup "${backupdir}" 209 assert_stderr --regexp "failed to backup config: failed copy .* to .*: stat .*: no such file or directory" 210 rm -rf -- "${backupdir:?}" 211 } 212 213 @test "cscli lapi status" { 214 rune -0 ./instance-crowdsec start 215 rune -0 cscli lapi status 216 217 assert_stderr --partial "Loaded credentials from" 218 assert_stderr --partial "Trying to authenticate with username" 219 assert_stderr --partial "You can successfully interact with Local API (LAPI)" 220 } 221 222 @test "cscli - missing LAPI credentials file" { 223 LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') 224 rm -f "${LOCAL_API_CREDENTIALS}" 225 rune -1 cscli lapi status 226 assert_stderr --partial "loading api client: while reading yaml file: open ${LOCAL_API_CREDENTIALS}: no such file or directory" 227 228 rune -1 cscli alerts list 229 assert_stderr --partial "loading api client: while reading yaml file: open ${LOCAL_API_CREDENTIALS}: no such file or directory" 230 231 rune -1 cscli decisions list 232 assert_stderr --partial "loading api client: while reading yaml file: open ${LOCAL_API_CREDENTIALS}: no such file or directory" 233 } 234 235 @test "cscli - empty LAPI credentials file" { 236 LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') 237 : > "${LOCAL_API_CREDENTIALS}" 238 rune -1 cscli lapi status 239 assert_stderr --partial "no credentials or URL found in api client configuration '${LOCAL_API_CREDENTIALS}'" 240 241 rune -1 cscli alerts list 242 assert_stderr --partial "no credentials or URL found in api client configuration '${LOCAL_API_CREDENTIALS}'" 243 244 rune -1 cscli decisions list 245 assert_stderr --partial "no credentials or URL found in api client configuration '${LOCAL_API_CREDENTIALS}'" 246 } 247 248 @test "cscli - missing LAPI client settings" { 249 config_set 'del(.api.client)' 250 rune -1 cscli lapi status 251 assert_stderr --partial "loading api client: no API client section in configuration" 252 253 rune -1 cscli alerts list 254 assert_stderr --partial "loading api client: no API client section in configuration" 255 256 rune -1 cscli decisions list 257 assert_stderr --partial "loading api client: no API client section in configuration" 258 } 259 260 @test "cscli - malformed LAPI url" { 261 LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') 262 config_set "${LOCAL_API_CREDENTIALS}" '.url="http://127.0.0.1:-80"' 263 264 rune -1 cscli lapi status -o json 265 rune -0 jq -r '.msg' <(stderr) 266 assert_output 'parsing api url: parse "http://127.0.0.1:-80/": invalid port ":-80" after host' 267 } 268 269 @test "cscli - bad LAPI password" { 270 rune -0 ./instance-crowdsec start 271 LOCAL_API_CREDENTIALS=$(config_get '.api.client.credentials_path') 272 config_set "${LOCAL_API_CREDENTIALS}" '.password="meh"' 273 274 rune -1 cscli lapi status -o json 275 rune -0 jq -r '.msg' <(stderr) 276 assert_output 'failed to authenticate to Local API (LAPI): API error: incorrect Username or Password' 277 } 278 279 @test "'cscli completion' with or without configuration file" { 280 rune -0 cscli completion bash 281 assert_output --partial "# bash completion for cscli" 282 rune -0 cscli completion zsh 283 assert_output --partial "# zsh completion for cscli" 284 rune -0 cscli completion powershell 285 assert_output --partial "# powershell completion for cscli" 286 rune -0 cscli completion fish 287 assert_output --partial "# fish completion for cscli" 288 289 rm "${CONFIG_YAML}" 290 rune -0 cscli completion bash 291 assert_output --partial "# bash completion for cscli" 292 } 293 294 @test "cscli support dump (smoke test)" { 295 rune -0 cscli support dump -f "$BATS_TEST_TMPDIR"/dump.zip 296 assert_file_exists "$BATS_TEST_TMPDIR"/dump.zip 297 } 298 299 @test "cscli explain" { 300 rune -0 ./instance-crowdsec start 301 line="Sep 19 18:33:22 scw-d95986 sshd[24347]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=1.2.3.4" 302 303 rune -0 cscli parsers install crowdsecurity/syslog-logs 304 rune -0 cscli collections install crowdsecurity/sshd 305 306 rune -0 cscli explain --log "$line" --type syslog --only-successful-parsers --crowdsec "$CROWDSEC" 307 assert_output - <"$BATS_TEST_DIRNAME"/testdata/explain/explain-log.txt 308 309 rune -0 cscli parsers remove --all --purge 310 rune -1 cscli explain --log "$line" --type syslog --crowdsec "$CROWDSEC" 311 assert_stderr --partial "unable to load parser dump result: no parser found. Please install the appropriate parser and retry" 312 } 313 314 @test 'Allow variable expansion and literal $ characters in passwords' { 315 export DB_PASSWORD='P@ssw0rd' 316 # shellcheck disable=SC2016 317 config_set '.db_config.password="$DB_PASSWORD"' 318 rune -0 cscli config show --key Config.DbConfig.Password 319 assert_output 'P@ssw0rd' 320 321 # shellcheck disable=SC2016 322 config_set '.db_config.password="$3cureP@ssw0rd"' 323 rune -0 cscli config show --key Config.DbConfig.Password 324 # shellcheck disable=SC2016 325 assert_output '$3cureP@ssw0rd' 326 327 config_set '.db_config.password="P@ssw0rd$"' 328 rune -0 cscli config show --key Config.DbConfig.Password 329 assert_output 'P@ssw0rd$' 330 } 331 332 @test "cscli doc" { 333 # generating documentation requires a directory named "doc" 334 335 cd "$BATS_TEST_TMPDIR" 336 rune -1 cscli doc 337 refute_output 338 assert_stderr --regexp 'failed to generate cobra doc: open doc/.*: no such file or directory' 339 340 mkdir -p doc 341 rune -0 cscli doc 342 refute_output 343 refute_stderr 344 assert_file_exists "doc/cscli.md" 345 assert_file_not_exist "doc/cscli_setup.md" 346 347 # commands guarded by feature flags are not documented unless the feature flag is set 348 349 export CROWDSEC_FEATURE_CSCLI_SETUP="true" 350 rune -0 cscli doc 351 assert_file_exists "doc/cscli_setup.md" 352 } 353 354 @test "feature.yaml for subcommands" { 355 # it is possible to enable subcommands with feature flags defined in feature.yaml 356 357 rune -1 cscli setup 358 assert_stderr --partial 'unknown command \"setup\" for \"cscli\"' 359 CONFIG_DIR=$(dirname "$CONFIG_YAML") 360 echo ' - cscli_setup' >> "$CONFIG_DIR"/feature.yaml 361 rune -0 cscli setup 362 assert_output --partial 'cscli setup [command]' 363 } 364 365 @test "cscli config feature-flags" { 366 # disabled 367 rune -0 cscli config feature-flags 368 assert_line '✗ cscli_setup: Enable cscli setup command (service detection)' 369 370 # enabled in feature.yaml 371 CONFIG_DIR=$(dirname "$CONFIG_YAML") 372 echo ' - cscli_setup' >> "$CONFIG_DIR"/feature.yaml 373 rune -0 cscli config feature-flags 374 assert_line '✓ cscli_setup: Enable cscli setup command (service detection)' 375 376 # enabled in environment 377 # shellcheck disable=SC2031 378 export CROWDSEC_FEATURE_CSCLI_SETUP="true" 379 rune -0 cscli config feature-flags 380 assert_line '✓ cscli_setup: Enable cscli setup command (service detection)' 381 382 # there are no retired features 383 rune -0 cscli config feature-flags --retired 384 }