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  }