Calendar: add FT sprint
[tails/test.git] / features / step_definitions / checks.rb
blobc3f0f7158370aeed6bb111ece37ed12a3d823fba
1 def shipped_openpgp_keys
2   shipped_gpg_keys = $vm.execute_successfully(
3     'gpg --batch --with-colons --fingerprint --list-key', user: LIVE_USER
4   ).stdout
5   openpgp_fingerprints = shipped_gpg_keys.scan(/^fpr:::::::::([A-Z0-9]+):$/)
6                                          .flatten
7   openpgp_fingerprints
8 end
10 Then /^the OpenPGP keys shipped with Tails are valid for the next (\d+) months$/ do |months|
11   invalid = []
12   shipped_openpgp_keys.each do |key|
13     begin
14       step "the shipped OpenPGP key #{key} are valid " \
15            "for the next #{months} months"
16     rescue Test::Unit::AssertionFailedError
17       invalid << key
18       next
19     end
20   end
21   assert(invalid.empty?,
22          'The following key(s) will not be valid ' \
23          "in #{months} months: #{invalid.join(', ')}")
24 end
26 Then /^the shipped (?:Debian repository key|OpenPGP key ([A-Z0-9]+)) are valid for the next (\d+) months$/ do |fingerprint, max_months|
27   if fingerprint
28     cmd = 'gpg'
29     user = LIVE_USER
30   else
31     fingerprint = TAILS_DEBIAN_REPO_KEY
32     cmd = 'apt-key adv'
33     user = 'root'
34   end
35   shipped_sig_key_info = $vm.execute_successfully(
36     "#{cmd} --batch --list-key #{fingerprint}", user: user
37   ).stdout
38   m = /\[expire[ds]: ([0-9-]*)\]/.match(shipped_sig_key_info)
39   if m
40     expiration_date = Date.parse(m[1])
41     assert((expiration_date << max_months.to_i) > DateTime.now,
42            "The shipped key #{fingerprint} will not be valid " \
43            "#{max_months} months from now.")
44   end
45 end
47 Then /^the live user has been setup by live\-boot$/ do
48   assert_vmcommand_success(
49     $vm.execute('test -e /var/lib/live/config/user-setup'),
50     'live-boot failed its user-setup'
51   )
52   actual_username = $vm.execute('. /etc/live/config/username.conf; ' \
53                                 'echo $LIVE_USERNAME').stdout.chomp
54   assert_equal(LIVE_USER, actual_username)
55 end
57 Then /^the live user is a member of only its own group and "(.*?)"$/ do |groups|
58   expected_groups = groups.split(' ') << LIVE_USER
59   actual_groups = $vm.execute("groups #{LIVE_USER}").stdout.chomp.sub(
60     /^#{LIVE_USER} : /, ''
61   ).split(' ')
62   unexpected = actual_groups - expected_groups
63   missing = expected_groups - actual_groups
64   assert_equal(0, unexpected.size,
65                "live user in unexpected groups #{unexpected}")
66   assert_equal(0, missing.size,
67                "live user not in expected groups #{missing}")
68 end
70 Then /^the live user owns its home dir and it has normal permissions$/ do
71   home = "/home/#{LIVE_USER}"
72   assert_vmcommand_success(
73     $vm.execute("test -d #{home}"),
74     "The live user's home doesn't exist or is not a directory"
75   )
76   owner = $vm.execute("stat -c %U:%G #{home}").stdout.chomp
77   perms = $vm.execute("stat -c %a #{home}").stdout.chomp
78   assert_equal("#{LIVE_USER}:#{LIVE_USER}", owner)
79   assert_equal('700', perms)
80 end
82 Then /^no unexpected services are listening for network connections$/ do
83   $vm.execute_successfully('ss -ltupn').stdout.chomp.split("\n").each do |line|
84     splitted = line.split(/[[:blank:]]+/)
85     proto = splitted[0]
86     next unless ['tcp', 'udp'].include?(proto)
88     laddr, lport = splitted[4].split(':')
89     proc = /users:\(\("([^"]+)"/.match(splitted[6])[1]
90     # Services listening on loopback is not a threat
91     if /127(\.[[:digit:]]{1,3}){3}/.match(laddr).nil?
92       if SERVICES_EXPECTED_ON_ALL_IFACES.include?([proc, laddr, lport]) ||
93          SERVICES_EXPECTED_ON_ALL_IFACES.include?([proc, laddr, '*'])
94         puts "Service '#{proc}' is listening on #{laddr}:#{lport} " \
95              'but has an exception'
96       else
97         raise "Unexpected service '#{proc}' listening on #{laddr}:#{lport}"
98       end
99     end
100   end
103 When /^Tails has booted a 64-bit kernel$/ do
104   assert_vmcommand_success($vm.execute("uname -r | grep -qs 'amd64$'"),
105                            'Tails has not booted a 64-bit kernel.')
108 Then /^the VirtualBox guest modules are available$/ do
109   assert_vmcommand_success($vm.execute('modinfo vboxguest'),
110                            'The vboxguest module is not available.')
113 Then /^the support documentation page opens in Tor Browser$/ do
114   if $language == 'German'
115     expected_title = 'Tails - Hilfe & Support'
116     expected_heading = 'Die Dokumentation durchsuchen'
117   else
118     expected_title = 'Tails - Support'
119     expected_heading = 'Search the documentation'
120   end
121   step "\"#{expected_title}\" has loaded in the Tor Browser"
122   browser_name = $language == 'German' ? 'Tor-Browser' : 'Tor Browser'
123   try_for(60) do
124     @torbrowser
125       .child(expected_title + " - #{browser_name}", roleName: 'frame')
126       .children(roleName: 'heading')
127       .any? { |heading| heading.text == expected_heading }
128   end
131 Given /^I plug and mount a USB drive containing a sample PNG$/ do
132   @png_dir = share_host_files(Dir.glob("#{MISC_FILES_DIR}/*.png"))
135 def mat2_show(file_in_guest)
136   $vm.execute_successfully("mat2 --show '#{file_in_guest}'",
137                            user: LIVE_USER).stdout
140 Then /^MAT can clean some sample PNG file$/ do
141   Dir.glob("#{MISC_FILES_DIR}/*.png").each do |png_on_host|
142     png_name = File.basename(png_on_host)
143     png_on_guest = "/home/#{LIVE_USER}/#{png_name}"
144     cleaned_png_on_guest = "/home/#{LIVE_USER}/#{png_name}".sub(/[.]png$/,
145                                                                 '.cleaned.png')
146     step "I copy \"#{@png_dir}/#{png_name}\" to \"#{png_on_guest}\" " \
147          "as user \"#{LIVE_USER}\""
148     raw_check_cmd = 'grep --quiet --fixed-strings --text ' \
149                     "'Created with GIMP'"
150     assert_vmcommand_success($vm.execute(raw_check_cmd + " '#{png_on_guest}'",
151                                          user: LIVE_USER),
152                              'The comment is not present in the PNG')
153     check_before = mat2_show(png_on_guest)
154     assert(check_before.include?("Metadata for #{png_on_guest}"),
155            "MAT failed to see that '#{png_on_host}' is dirty")
156     $vm.execute_successfully("mat2 '#{png_on_guest}'", user: LIVE_USER)
157     check_after = mat2_show(cleaned_png_on_guest)
158     assert(check_after.include?('No metadata found'),
159            "MAT failed to clean '#{png_on_host}'")
160     assert($vm.execute(raw_check_cmd + " '#{cleaned_png_on_guest}'",
161                        user: LIVE_USER).failure?,
162            'The comment is still present in the PNG')
163     $vm.execute_successfully("rm '#{png_on_guest}'")
164   end
167 Then /^AppArmor is enabled$/ do
168   assert_vmcommand_success($vm.execute('aa-status'),
169                            'AppArmor is not enabled')
172 Then /^some AppArmor profiles are enforced$/ do
173   assert($vm.execute('aa-status --enforced').stdout.chomp.to_i.positive?,
174          'No AppArmor profile is enforced')
177 def get_seccomp_status(process)
178   assert($vm.process_running?(process), "Process #{process} not running.")
179   pid = $vm.pidof(process)[0]
180   status = $vm.file_content("/proc/#{pid}/status")
181   status.match(/^Seccomp:\s+([0-9])/)[1].chomp.to_i
184 def get_apparmor_status(pid)
185   apparmor_status = $vm.file_content("/proc/#{pid}/attr/current").chomp
186   if apparmor_status.include?(')')
187     # matches something like     /usr/sbin/cupsd (enforce)
188     # and only returns what's in the parentheses
189     apparmor_status.match(/[^\s]+\s+\((.+)\)$/)[1].chomp
190   else
191     apparmor_status
192   end
195 Then /^the running process "(.+)" is confined with AppArmor in (complain|enforce) mode$/ do |process, mode|
196   assert($vm.process_running?(process), "Process #{process} not running.")
197   pid = $vm.pidof(process)[0]
198   assert_equal(mode, get_apparmor_status(pid))
201 Then /^the running process "(.+)" is confined with Seccomp in (filter|strict) mode$/ do |process, mode|
202   status = get_seccomp_status(process)
203   if mode == 'strict'
204     assert_equal(1, status,
205                  "#{process} not confined with Seccomp in strict mode")
206   elsif mode == 'filter'
207     assert_equal(2, status,
208                  "#{process} not confined with Seccomp in filter mode")
209   else
210     raise "Unsupported mode #{mode} passed"
211   end
214 When /^I disable all networking in the Tails Greeter$/ do
215   open_greeter_additional_settings
216   @screen.wait('TailsGreeterNetworkConnection.png', 30).click
217   @screen.wait('TailsGreeterDisableAllNetworking.png', 10).click
218   @screen.wait('TailsGreeterAdditionalSettingsAdd.png', 10).click
221 Then /^the Tor Status icon tells me that Tor is( not)? usable$/ do |not_usable|
222   picture = not_usable ? 'TorStatusNotUsable' : 'TorStatusUsable'
223   @screen.find("#{picture}.png")