inspec-core 4.31.1 → 4.37.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -1
  3. data/inspec-core.gemspec +2 -2
  4. data/lib/inspec/base_cli.rb +5 -3
  5. data/lib/inspec/cli.rb +12 -4
  6. data/lib/inspec/control_eval_context.rb +1 -0
  7. data/lib/inspec/fetcher/local.rb +1 -1
  8. data/lib/inspec/input.rb +39 -4
  9. data/lib/inspec/input_registry.rb +1 -0
  10. data/lib/inspec/objects/input.rb +1 -1
  11. data/lib/inspec/plugin/v2/loader.rb +9 -0
  12. data/lib/inspec/profile_context.rb +1 -1
  13. data/lib/inspec/reporters/cli.rb +63 -0
  14. data/lib/inspec/resources.rb +1 -0
  15. data/lib/inspec/resources/command.rb +3 -9
  16. data/lib/inspec/resources/groups.rb +21 -6
  17. data/lib/inspec/resources/http.rb +1 -1
  18. data/lib/inspec/resources/mssql_session.rb +1 -1
  19. data/lib/inspec/resources/mysql_session.rb +1 -1
  20. data/lib/inspec/resources/pip.rb +1 -1
  21. data/lib/inspec/resources/registry_key.rb +1 -1
  22. data/lib/inspec/resources/selinux.rb +154 -0
  23. data/lib/inspec/resources/users.rb +1 -1
  24. data/lib/inspec/resources/windows_feature.rb +2 -1
  25. data/lib/inspec/resources/windows_firewall_rule.rb +1 -1
  26. data/lib/inspec/rule.rb +9 -1
  27. data/lib/inspec/runner.rb +1 -1
  28. data/lib/inspec/utils/erlang_parser.rb +2 -2
  29. data/lib/inspec/utils/filter.rb +7 -7
  30. data/lib/inspec/utils/nginx_parser.rb +3 -3
  31. data/lib/inspec/version.rb +1 -1
  32. data/lib/plugins/inspec-compliance/README.md +125 -2
  33. data/lib/plugins/inspec-compliance/lib/inspec-compliance.rb +5 -0
  34. data/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb +18 -1
  35. data/lib/plugins/inspec-compliance/lib/inspec-compliance/api/login.rb +23 -8
  36. data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +24 -25
  37. data/lib/plugins/inspec-compliance/lib/inspec-compliance/target.rb +5 -4
  38. metadata +11 -4
@@ -56,7 +56,7 @@ module Inspec::Resources
56
56
  end
57
57
 
58
58
  def body
59
- @worker.body
59
+ @worker.body&.force_encoding(Encoding::UTF_8)
60
60
  end
61
61
 
62
62
  def http_method
@@ -58,7 +58,7 @@ module Inspec::Resources
58
58
  end
59
59
 
60
60
  def query(q) # rubocop:disable Metrics/PerceivedComplexity
61
- escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '""').gsub(/\$/, '\\$')
61
+ escaped_query = q.gsub(/\\/, "\\\\").gsub(/"/, '""').gsub(/\$/, '\\$')
62
62
  # surpress 'x rows affected' in SQLCMD with 'set nocount on;'
63
63
  cmd_string = "sqlcmd -Q \"set nocount on; #{escaped_query}\" -W -w 1024 -s ','"
64
64
  cmd_string += " -U '#{@user}' -P '#{@password}'" unless @user.nil? || @password.nil?
@@ -75,7 +75,7 @@ module Inspec::Resources
75
75
  def create_mysql_cmd(q, db = "")
76
76
  # TODO: simple escape, must be handled by a library
77
77
  # that does this securely
78
- escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$')
78
+ escaped_query = q.gsub(/\\/, "\\\\").gsub(/"/, '\\"').gsub(/\$/, '\\$')
79
79
 
80
80
  # construct the query
81
81
  command = "mysql"
@@ -117,7 +117,7 @@ module Inspec::Resources
117
117
  if defined?(windows_paths["Python"]) && pipcmd.nil?
118
118
  return nil if windows_paths["Pip"].nil?
119
119
 
120
- pipdir = windows_paths["Python"].split('\\')
120
+ pipdir = windows_paths["Python"].split("\\")
121
121
  # remove python.exe
122
122
  pipdir.pop
123
123
  pipcmd = pipdir.push("Scripts").push("pip.exe").join("/")
@@ -281,7 +281,7 @@ module Inspec::Resources
281
281
  key = @options[:key]
282
282
  return "" unless key
283
283
 
284
- key.start_with?('\\') ? key : "\\#{key}"
284
+ key.start_with?("\\") ? key : "\\#{key}"
285
285
  end
286
286
  end
287
287
 
@@ -0,0 +1,154 @@
1
+ require "inspec/resources/command"
2
+ require "inspec/utils/filter"
3
+
4
+ module Inspec::Resources
5
+ class SelinuxModuleFilter
6
+ # use filtertable for SELinux Modules
7
+ filter = FilterTable.create
8
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
9
+ filter.register_column(:names, field: :name)
10
+ filter.register_column(:status, field: :status)
11
+ filter.register_column(:states, field: :state)
12
+ filter.register_column(:priorities , field: :priority)
13
+ filter.register_custom_matcher(:enabled?) { |x| x.states[0] == "enabled" }
14
+ filter.register_custom_matcher(:installed?) { |x| x.status[0] == "installed" }
15
+ filter.install_filter_methods_on_resource(self, :modules)
16
+
17
+ attr_reader :modules
18
+ def initialize(modules)
19
+ @modules = modules
20
+ end
21
+
22
+ def to_s
23
+ "SELinux modules"
24
+ end
25
+ end
26
+
27
+ class SelinuxBooleanFilter
28
+ # use filtertable for SELinux Booleans
29
+ filter = FilterTable.create
30
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
31
+ filter.register_column(:names, field: :name)
32
+ filter.register_column(:states, field: :state)
33
+ filter.register_column(:defaults, field: :default)
34
+ filter.register_custom_matcher(:on?) { |x| x.states[0] == "on" }
35
+ filter.install_filter_methods_on_resource(self, :booleans)
36
+
37
+ attr_reader :booleans
38
+ def initialize(booleans)
39
+ @booleans = booleans
40
+ end
41
+
42
+ def to_s
43
+ "SELinux booleans"
44
+ end
45
+ end
46
+
47
+ class Selinux < Inspec.resource(1)
48
+ name "selinux"
49
+ supports platform: "linux"
50
+
51
+ desc "Use the selinux Chef InSpec resource to test the configuration data of the SELinux policy, SELinux modules, and SELinux booleans."
52
+
53
+ example <<~EXAMPLE
54
+ describe selinux do
55
+ it { should be_installed }
56
+ it { should be_disabled }
57
+ it { should be_permissive }
58
+ it { should be_enforcing }
59
+ end
60
+
61
+ describe selinux do
62
+ its('policy') { should eq "targeted"}
63
+ end
64
+
65
+ describe selinux.modules.where("zebra") do
66
+ it { should exist }
67
+ it { should be_installed }
68
+ it { should be_enabled }
69
+ end
70
+
71
+ describe selinux.modules.where(status: "installed") do
72
+ it { should exist }
73
+ its('count') { should cmp 404 }
74
+ end
75
+
76
+ describe selinux.booleans.where(name: "xend_run_blktap") do
77
+ it { should be_on }
78
+ end
79
+
80
+ describe selinux.booleans.where { name == "xend_run_blktap" && state == "on" } do
81
+ it { should exist }
82
+ end
83
+ EXAMPLE
84
+
85
+ def initialize(selinux_path = "/etc/selinux/config")
86
+ @path = selinux_path
87
+ cmd = inspec.command("sestatus")
88
+
89
+ if cmd.exit_status != 0
90
+ # `sestatus` command not found error message comes in stdout so handling both here
91
+ out = cmd.stdout + "\n" + cmd.stderr
92
+ return skip_resource "Skipping resource: #{out}"
93
+ end
94
+
95
+ result = cmd.stdout.delete(" ").gsub(/\n/, ",").gsub(/\r/, "").downcase
96
+ @data = Hash[result.scan(/([^:]+):([^,]+)[,$]/)]
97
+ end
98
+
99
+ def installed?
100
+ inspec.file(@path).exist?
101
+ end
102
+
103
+ def disabled?
104
+ @data["selinuxstatus"] == "disabled"
105
+ end
106
+
107
+ def enforcing?
108
+ @data["currentmode"] == "enforcing"
109
+ end
110
+
111
+ def permissive?
112
+ @data["currentmode"] == "permissive"
113
+ end
114
+
115
+ def policy
116
+ @data["loadedpolicyname"]
117
+ end
118
+
119
+ def modules
120
+ SelinuxModuleFilter.new(parse_modules)
121
+ end
122
+
123
+ def booleans
124
+ SelinuxBooleanFilter.new(parse_booleans)
125
+ end
126
+
127
+ def to_s
128
+ "SELinux"
129
+ end
130
+
131
+ private
132
+
133
+ def parse_modules
134
+ raw_modules = inspec.command("semodule -lfull").stdout
135
+ r_modules = []
136
+ raw_modules.each_line do |entry|
137
+ data = entry.split.map(&:strip)
138
+ state = data.length == 4 ? data[3] : "enabled"
139
+ r_modules.push({ name: data[1], status: "installed", state: state, priority: data[0] })
140
+ end
141
+ r_modules
142
+ end
143
+
144
+ def parse_booleans
145
+ raw_booleans = inspec.command("semanage boolean -l -n").stdout
146
+ r_booleans = []
147
+ raw_booleans.each_line do |entry|
148
+ data = entry.scan(/([^(,)]+)/).flatten.map(&:strip)
149
+ r_booleans.push({ name: data[0], state: data[1], default: data[2] })
150
+ end
151
+ r_booleans
152
+ end
153
+ end
154
+ end
@@ -611,7 +611,7 @@ module Inspec::Resources
611
611
  # @see https://msdn.microsoft.com/en-us/library/aa394153(v=vs.85).aspx
612
612
  class WindowsUser < UserInfo
613
613
  def parse_windows_account(username)
614
- account = username.split('\\')
614
+ account = username.split("\\")
615
615
  name = account.pop
616
616
  domain = account.pop unless account.empty?
617
617
  [name, domain]
@@ -79,10 +79,11 @@ module Inspec::Resources
79
79
  result = cmd.stdout
80
80
  feature_name_regex = /Feature Name : (.*)(\r\n|\n)/
81
81
  description_regex = /Description : (.*)(\r\n|\n)/
82
+ state_regex = /State : (.*)(\r\n|\n)/
82
83
  feature_info = {
83
84
  name: result.match(feature_name_regex).captures[0].chomp,
84
85
  description: result.match(description_regex).captures[0].chomp,
85
- installed: true,
86
+ installed: result.match(state_regex).captures[0].chomp == 'Enabled',
86
87
  }
87
88
  end
88
89
 
@@ -105,7 +105,7 @@ module Inspec::Resources
105
105
  # @see https://github.com/chef/chef/blob/master/lib/chef/resource/windows_firewall_rule.rb
106
106
  def load_firewall_state(rule_name)
107
107
  <<-EOH
108
- Remove-TypeData System.Array # workaround for PS bug here: https://bit.ly/2SRMQ8M
108
+ Get-TypeData -TypeName System.Array | Remove-TypeData # workaround for PS bug here: https://bit.ly/2SRMQ8M
109
109
  $rule = Get-NetFirewallRule -Name "#{rule_name}"
110
110
  $addressFilter = $rule | Get-NetFirewallAddressFilter
111
111
  $portFilter = $rule | Get-NetFirewallPortFilter
data/lib/inspec/rule.rb CHANGED
@@ -180,7 +180,15 @@ module Inspec
180
180
  options[:priority] ||= 20
181
181
  options[:provider] = :inline_control_code
182
182
  evt = Inspec::Input.infer_event(options)
183
- Inspec::InputRegistry.find_or_register_input(input_name, __profile_id, event: evt).value
183
+ Inspec::InputRegistry.find_or_register_input(
184
+ input_name,
185
+ __profile_id,
186
+ type: options[:type],
187
+ required: options[:required],
188
+ description: options[:description],
189
+ pattern: options[:pattern],
190
+ event: evt
191
+ ).value
184
192
  end
185
193
  end
186
194
 
data/lib/inspec/runner.rb CHANGED
@@ -243,7 +243,7 @@ module Inspec
243
243
  # to provide access to local profiles that add resources.
244
244
  @depends.each do |dep|
245
245
  # support for windows paths
246
- dep = dep.tr('\\', "/")
246
+ dep = dep.tr("\\", "/")
247
247
  Inspec::Profile.for_path(dep, { profile_context: ctx }).load_libraries
248
248
  end
249
249
 
@@ -52,13 +52,13 @@ class ErlangParser < Parslet::Parser
52
52
 
53
53
  rule(:stringS) do
54
54
  str("'") >> (
55
- str('\\') >> any | str("'").absent? >> any
55
+ str("\\") >> any | str("'").absent? >> any
56
56
  ).repeat.as(:string) >> str("'") >> filler?
57
57
  end
58
58
 
59
59
  rule(:stringD) do
60
60
  str('"') >> (
61
- str('\\') >> any | str('"').absent? >> any
61
+ str("\\") >> any | str('"').absent? >> any
62
62
  ).repeat.as(:string) >> str('"') >> filler?
63
63
  end
64
64
 
@@ -375,13 +375,13 @@ module FilterTable
375
375
  methods_to_install_on_resource_class = @filter_methods + @custom_properties.keys
376
376
  methods_to_install_on_resource_class.each do |method_name|
377
377
  resource_class.send(:define_method, method_name) do |*args, &block|
378
- begin
379
- # self here is the resource instance
380
- filter_table_instance = table_class.new(self, send(raw_data_fetcher_method_name), " with")
381
- filter_table_instance.send(method_name, *args, &block)
382
- rescue Inspec::Exceptions::ResourceFailed, Inspec::Exceptions::ResourceSkipped => e
383
- FilterTable::ExceptionCatcher.new(resource_class, e)
384
- end
378
+
379
+ # self here is the resource instance
380
+ filter_table_instance = table_class.new(self, send(raw_data_fetcher_method_name), " with")
381
+ filter_table_instance.send(method_name, *args, &block)
382
+ rescue Inspec::Exceptions::ResourceFailed, Inspec::Exceptions::ResourceSkipped => e
383
+ FilterTable::ExceptionCatcher.new(resource_class, e)
384
+
385
385
  end
386
386
  end
387
387
  end
@@ -31,19 +31,19 @@ class NginxParser < Parslet::Parser
31
31
 
32
32
  rule(:standard_value) do
33
33
  ((match(/[#;{'"]/).absent? >> any) >> (
34
- str('\\') >> any | match('[#;{]|\s').absent? >> any
34
+ str("\\") >> any | match('[#;{]|\s').absent? >> any
35
35
  ).repeat).as(:value) >> space.repeat
36
36
  end
37
37
 
38
38
  rule(:single_quoted_value) do
39
39
  str("'") >> (
40
- str('\\') >> any | str("'").absent? >> any
40
+ str("\\") >> any | str("'").absent? >> any
41
41
  ).repeat.as(:value) >> str("'") >> space.repeat
42
42
  end
43
43
 
44
44
  rule(:double_quoted_value) do
45
45
  str('"') >> (
46
- str('\\') >> any | str('"').absent? >> any
46
+ str("\\") >> any | str('"').absent? >> any
47
47
  ).repeat.as(:value) >> str('"') >> space.repeat
48
48
  end
49
49
 
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.31.1".freeze
2
+ VERSION = "4.37.8".freeze
3
3
  end
@@ -6,24 +6,50 @@ This extensions offers the following features:
6
6
  - execute profiles directly from Chef Automate/Chef Compliance locally
7
7
  - upload a local profile to Chef Automate/Chef Compliance
8
8
 
9
+ `inspec compliance` is a backwards compatible alias for `inspec automate` and works the same way.
10
+
9
11
  To use the CLI, this InSpec add-on adds the following commands:
10
12
 
13
+ * `$ inspec automate login` - authentication of the API token against Chef Automate/Chef Compliance
14
+ * `$ inspec automate profiles` - list all available Compliance profiles
15
+ * `$ inspec exec compliance://profile` - runs a Compliance profile
16
+ * `$ inspec automate upload path/to/local/profile` - uploads a local profile to Chef Automate/Chef Compliance
17
+ * `$ inspec automate logout` - logout of Chef Automate/Chef Compliance
18
+
19
+ Similar to these CLI commands are:
20
+
11
21
  * `$ inspec compliance login` - authentication of the API token against Chef Automate/Chef Compliance
12
22
  * `$ inspec compliance profiles` - list all available Compliance profiles
13
- * `$ inspec exec compliance://profile` - runs a Compliance profile
14
23
  * `$ inspec compliance upload path/to/local/profile` - uploads a local profile to Chef Automate/Chef Compliance
15
24
  * `$ inspec compliance logout` - logout of Chef Automate/Chef Compliance
16
25
 
17
26
  Compliance profiles can be executed in two ways:
18
27
 
19
- - via compliance exec: `inspec compliance exec profile`
28
+ - via compliance exec: `inspec automate exec profile` or `inspec compliance exec profile`
20
29
  - via compliance scheme: `inspec exec compliance://profile`
21
30
 
22
31
 
32
+
33
+
23
34
  ## Usage
24
35
 
25
36
  ### Command options
26
37
 
38
+ ```
39
+ $ inspec automate
40
+ Commands:
41
+ inspec automate download PROFILE # downloads a profile from Chef Compliance
42
+ inspec automate exec PROFILE # executes a Chef Compliance profile
43
+ inspec automate help [COMMAND] # Describe subcommands or one specific subcommand
44
+ inspec automate login SERVER # Log in to a Chef Automate/Chef Compliance SERVER
45
+ inspec automate logout # user logout from Chef Compliance
46
+ inspec automate profiles # list all available profiles in Chef Compliance
47
+ inspec automate upload PATH # uploads a local profile to Chef Compliance
48
+ inspec automate version # displays the version of the Chef Compliance server
49
+ ```
50
+
51
+ or
52
+
27
53
  ```
28
54
  $ inspec compliance
29
55
  Commands:
@@ -41,6 +67,12 @@ Commands:
41
67
 
42
68
  You will need an API token for authentication. You can retrieve one via the admin section of your A2 web gui.
43
69
 
70
+ ```
71
+ $ inspec automate login https://automate2.compliance.test --insecure --user 'admin' --token 'zuop..._KzE'
72
+ ```
73
+
74
+ or
75
+
44
76
  ```
45
77
  $ inspec compliance login https://automate2.compliance.test --insecure --user 'admin' --token 'zuop..._KzE'
46
78
  ```
@@ -63,6 +95,12 @@ Example:
63
95
 
64
96
  You will need an access token for authentication. You can retrieve one via [UI](https://docs.chef.io/api_delivery.html) or [CLI](https://docs.chef.io/ctl_delivery.html#delivery-token).
65
97
 
98
+ ```
99
+ $ inspec automate login https://automate.compliance.test --insecure --user 'admin' --ent 'brewinc' --token 'zuop..._KzE'
100
+ ```
101
+
102
+ or
103
+
66
104
  ```
67
105
  $ inspec compliance login https://automate.compliance.test --insecure --user 'admin' --ent 'brewinc' --token 'zuop..._KzE'
68
106
  ```
@@ -75,12 +113,42 @@ You will need an access token for authentication. You can retrieve one via:
75
113
 
76
114
  You can choose the access token (`--token`) or the refresh token (`--refresh_token`)
77
115
 
116
+ ```
117
+ $ inspec automate login https://compliance.test --user admin --insecure --token '...'
118
+ ```
119
+
120
+ or
121
+
78
122
  ```
79
123
  $ inspec compliance login https://compliance.test --user admin --insecure --token '...'
80
124
  ```
81
125
 
82
126
  ### List available profiles via Chef Compliance / Automate
83
127
 
128
+ ```
129
+ $ inspec automate profiles
130
+ Available profiles:
131
+ -------------------
132
+ * base/apache
133
+ * base/linux
134
+ * base/mysql
135
+ * base/postgres
136
+ * base/ssh
137
+ * base/windows
138
+ * cis/cis-centos6-level1
139
+ * cis/cis-centos6-level2
140
+ * cis/cis-centos7-level1
141
+ * cis/cis-centos7-level2
142
+ * cis/cis-rhel7-level1
143
+ * cis/cis-rhel7-level2
144
+ * cis/cis-ubuntu12.04lts-level1
145
+ * cis/cis-ubuntu12.04lts-level2
146
+ * cis/cis-ubuntu14.04lts-level1
147
+ * cis/cis-ubuntu14.04lts-level2
148
+ ```
149
+
150
+ or
151
+
84
152
  ```
85
153
  $ inspec compliance profiles
86
154
  Available profiles:
@@ -105,6 +173,47 @@ Available profiles:
105
173
 
106
174
  ### Upload a profile to Chef Compliance / Automate
107
175
 
176
+ ```
177
+ $ inspec automate version
178
+ Chef Compliance version: 1.0.11
179
+ ➜ inspec git:(chris-rock/cc-error-not-loggedin) ✗ b inspec automate upload examples/profile
180
+ I, [2016-05-06T14:27:20.907547 #37592] INFO -- : Checking profile in examples/profile
181
+ I, [2016-05-06T14:27:20.907668 #37592] INFO -- : Metadata OK.
182
+ I, [2016-05-06T14:27:20.968584 #37592] INFO -- : Found 4 controls.
183
+ I, [2016-05-06T14:27:20.968638 #37592] INFO -- : Control definitions OK.
184
+ Profile is valid
185
+ Generate temporary profile archive at /var/folders/jy/2bnrfb4s36jbjtzllvhhyqhw0000gn/T/profile20160506-37592-1tf326f.tar.gz
186
+ I, [2016-05-06T14:27:21.020017 #37592] INFO -- : Generate archive /var/folders/jy/2bnrfb4s36jbjtzllvhhyqhw0000gn/T/profile20160506-37592-1tf326f.tar.gz.
187
+ I, [2016-05-06T14:27:21.024837 #37592] INFO -- : Finished archive generation.
188
+ Start upload to admin/profile
189
+ Uploading to Chef Compliance
190
+ Successfully uploaded profile
191
+
192
+ # display all profiles
193
+ $ inspec automate profiles
194
+ Available profiles:
195
+ -------------------
196
+ * admin/profile
197
+ * base/apache
198
+ * base/linux
199
+ * base/mysql
200
+ * base/postgres
201
+ * base/ssh
202
+ * base/windows
203
+ * cis/cis-centos6-level1
204
+ * cis/cis-centos6-level2
205
+ * cis/cis-centos7-level1
206
+ * cis/cis-centos7-level2
207
+ * cis/cis-rhel7-level1
208
+ * cis/cis-rhel7-level2
209
+ * cis/cis-ubuntu12.04lts-level1
210
+ * cis/cis-ubuntu12.04lts-level2
211
+ * cis/cis-ubuntu14.04lts-level1
212
+ * cis/cis-ubuntu14.04lts-level2
213
+ ```
214
+
215
+ or
216
+
108
217
  ```
109
218
  $ inspec compliance version
110
219
  Chef Compliance version: 1.0.11
@@ -168,17 +277,31 @@ $ inspec exec compliance://admin/apache-baseline#2.0.1
168
277
  ```
169
278
 
170
279
  Download a specific version(2.0.2) of a profile when logged in with Automate:
280
+ ```
281
+ $ inspec automate download compliance://admin/apache-baseline#2.0.2
282
+ ```
283
+
284
+ or
285
+
171
286
  ```
172
287
  $ inspec compliance download compliance://admin/apache-baseline#2.0.2
173
288
  ```
174
289
 
175
290
  ### To Logout from Chef Compliance
176
291
 
292
+ ```
293
+ $ inspec automate logout
294
+ Successfully logged out
295
+ ```
296
+
297
+ or
298
+
177
299
  ```
178
300
  $ inspec compliance logout
179
301
  Successfully logged out
180
302
  ```
181
303
 
304
+
182
305
  ## Integration Tests
183
306
 
184
307
  At this point of time, InSpec is not able to pick up the token directly, therefore the integration test is semi-automatic at this point of time: