cockpit/test/verify/check-docker

682 lines
29 KiB
Python
Executable File

#!/usr/bin/python3
# This file is part of Cockpit.
#
# Copyright (C) 2014 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
import json
import os
import parent
from testlib import *
@skipPackage("cockpit-docker")
@skipImage("No docker packaged", "rhel-8-1", "rhel-8-1-distropkg", "rhel-8-2")
@skipImage("Not supporting cockpit-docker on CoreOS", "fedora-coreos")
@skipImage("Docker not available", "fedora-31") # https://github.com/cockpit-project/cockpit/issues/12670
class TestDocker(MachineCase):
def setUp(self):
MachineCase.setUp(self)
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
def confirm(self):
b = self.browser
b.wait_popup("confirmation-dialog")
b.click("#confirmation-dialog-confirm")
# popdown should be really quick
with b.wait_timeout(5):
b.wait_popdown("confirmation-dialog")
def deleteImageConfirm(self):
b = self.browser
b.wait_popup('delete-image-confirmation-dialog')
b.click('#delete-image-confirmation-dialog-confirm')
# popdown could be delayed because of running containers
with b.wait_timeout(20):
b.wait_popdown('delete-image-confirmation-dialog')
def del_container_from_details(self, container_name):
b = self.browser
b.click("#container-details-delete")
with b.wait_timeout(20):
try:
self.confirm()
b.wait_not_in_text("#containers-containers", container_name)
except Error:
# we may have to confirm again for forced deletion
self.confirm()
b.wait_not_in_text("#containers-containers", container_name)
def wait_for_message(self, message):
b = self.browser
# sometimes container output is missing from the logs
# https://github.com/docker/docker/issues/10617
b.wait_in_text("#container-terminal", message)
def testBasic(self):
b = self.browser
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
message = "HelloMessage."
# show all containers to interact with stopped ones
b.wait_in_text("#containers-containers-filter", "Images and running containers")
b.set_val("#containers-containers-filter", "all")
b.wait_in_text("#containers-containers-filter", "Everything")
# Run it
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "PROBE1")
b.set_val("#containers-run-image-command", """/bin/sh -c 'echo "%s"; sleep 5' """ % message)
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
b.wait_in_text("#containers-containers", "PROBE1")
b.wait_in_text("#containers-containers", "busybox:latest")
# Check output of the probe
b.click('#containers-containers tr:contains("PROBE1")')
b.wait_visible('#container-details')
# The terminal uses NO-BREAK SPACE so we check for that here
self.wait_for_message(message)
b.wait_in_text("#container-details-state", "Exited")
self.del_container_from_details("PROBE1")
# Run it without TTY and make sure it keeps running so that we
# can link to it.
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "PROBE1")
b.set_val("#containers-run-image-command", "/bin/sh -c 'echo \"%s\"; sleep 10000'" % (message))
b.click("#containers-run-image-with-terminal")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
b.wait_in_text("#containers-containers", "PROBE1")
# Check not linked
info = json.loads(m.execute('docker inspect PROBE1'))
self.assertEqual(info[0]["HostConfig"]["Links"], None)
# Create another container linked to old one
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "PROBE2")
b.set_val("#containers-run-image-command", "/bin/echo -e '%s\n%s\n'" % (message, message))
b.click("#containers-run-image-with-terminal")
b.wait_visible("#select-linked-containers:empty")
b.click("#link-containers")
b.wait_visible("#select-linked-containers:parent")
b.click("#select-linked-containers form:last-child .link-container button")
b.click("#select-linked-containers form:last-child .link-container a[value='PROBE1']")
b.set_val("#select-linked-containers form:last-child input[name='alias']", "alias1")
b.click("#select-linked-containers form:last-child button.fa-plus")
# new line should be the second group
b.wait_present("#select-linked-containers .form-group:eq(1)")
b.click("#select-linked-containers form:last-child .link-container button")
b.click("#select-linked-containers form:last-child .link-container a[value='PROBE1']")
b.set_val("#select-linked-containers form:last-child input[name='alias']", "alias2")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
b.wait_in_text("#containers-containers", "PROBE2")
# Wait for PROBE2 to Exit
b.click('#containers-containers tr:contains("PROBE2")')
b.wait_in_text("#container-details-state", "Exited")
# Check links
info = json.loads(m.execute('docker inspect PROBE2'))
self.assertEqual(set(info[0]["HostConfig"]["Links"]),
set(["/PROBE1:/PROBE2/alias1", "/PROBE1:/PROBE2/alias2"]))
# delete PROBE2 from dash
b.click("#container-details .content-filter a")
b.wait_visible("#containers-containers")
b.wait_in_text('#containers-containers', "PROBE2")
b.click('#containers-containers tbody tr:contains("PROBE2") td.listing-ct-toggle')
b.click('#containers-containers tbody tr:contains("PROBE2") + tr button.btn-delete')
with b.wait_timeout(20):
try:
b.wait_not_in_text('#containers-containers', "PROBE2")
except Error:
self.confirm()
b.wait_not_in_text('#containers-containers', "PROBE2")
# Check output of PROBE1
b.click('#containers-containers tr:contains("PROBE1")')
b.wait_visible("#container-details")
b.wait_in_text('#container-details', "busybox:latest")
self.wait_for_message(message)
b.call_js_func("ph_count_check", ".console-ct pre", 1)
b.click("#container-details-stop")
b.wait_in_text("#container-details-state", "Exited")
# Make sure after restart we only have one
b.click("#container-details-start")
self.wait_for_message("%s\n%s" % (message, message))
b.call_js_func("ph_count_check", ".console-ct pre", 1)
b.click("#container-details-stop")
b.wait_in_text("#container-details-state", "Exited")
# Delete the container from the image-details page
b.click("#container-details .content-filter a")
b.click('#containers-images tr:contains("busybox:latest")')
b.wait_visible("#image-details")
b.wait_present(".image-details-used")
b.wait_visible(".image-details-used tr td:first-child")
b.click(".image-details-used .enable-danger")
b.click(".image-details-used .btn-delete")
b.wait_not_present(".image-details-used tr td")
# Delete image itself
b.click("#image-details-delete")
self.deleteImageConfirm()
b.wait_visible("#containers")
b.wait_not_in_text('#containers-images', 'busybox:latest')
def testDeleteImages(self):
b = self.browser
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
# Deleting an image without depending containers has no container list
b.click('#containers-images tr:contains("busybox:latest") td.listing-ct-toggle')
b.click('#containers-images tr:contains("busybox:latest") + tr .btn-delete')
b.wait_popup('delete-image-confirmation-dialog')
self.assertFalse(b.is_visible('#delete-image-confirmation-dialog-containers'))
b.click('#delete-image-confirmation-dialog-cancel')
b.wait_popdown('delete-image-confirmation-dialog')
b.click('#containers-images tr:contains("busybox:latest") td.listing-ct-toggle')
# Create some containers
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup('containers_run_image_dialog')
b.set_val('#containers-run-image-name', 'C1')
b.click('#containers-run-image-run')
b.wait_popdown('containers_run_image_dialog')
b.wait_in_text('#containers-containers', 'C1')
b.wait_in_text('#containers-containers', 'busybox:latest')
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup('containers_run_image_dialog')
b.set_val('#containers-run-image-name', 'C2')
b.click('#containers-run-image-run')
b.wait_popdown('containers_run_image_dialog')
b.wait_in_text('#containers-containers', 'C2')
b.wait_in_text('#containers-containers', 'busybox:latest')
# Delete image itself without deleting depending containers
b.click('#containers-images tr:contains("busybox:latest")')
b.click('#image-details-delete')
b.wait_popup('delete-image-confirmation-dialog')
b.wait_visible('#delete-image-confirmation-dialog-containers')
# Delete image with running containers
b.click('#image-details-delete')
b.wait_popup('delete-image-confirmation-dialog')
b.wait_in_text('#delete-image-confirmation-dialog-confirm', 'Stop and delete')
self.deleteImageConfirm()
b.wait_visible('#containers')
b.wait_not_present('#containers-images tr:contains("busybox:latest")')
def testExpose(self):
b = self.browser
m = self.machine
self.allow_journal_messages('.*denied.*name_connect.*docker.*')
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
port = 3380
message = "HelloMessage."
# Create an updated image, expose a port
m.execute("mkdir /var/tmp/container-probe")
m.upload(["verify/files/listen-on-port.sh"], "/var/tmp/container-probe")
m.execute("""echo -e '
FROM busybox
MAINTAINER cockpit
EXPOSE %(port)d
ADD listen-on-port.sh /listen-on-port.sh
CMD ["/listen-on-port.sh", "%(port)d", "%(message)s"]
' > /var/tmp/container-probe/Dockerfile""" % {'message': message, 'port': port})
image_name = "test/container-probe"
m.execute("docker build -t %s /var/tmp/container-probe" % (image_name))
m.execute("rm -rf /var/tmp/container-probe")
# Wait for it to appear
b.wait_in_text("#containers-images", image_name)
nport = port + 1
# Run it and expose additional port via the ui
b.click("#containers-images tr:contains(\"%s\") button.fa-play" % (image_name))
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "PROBE2")
# Tell our probe to listen on both ports
second_message = "%s" % (message)
b.set_val("#containers-run-image-command",
("/bin/sh -c \"/listen-on-port.sh %(port)d %(message)s; " +
"/listen-on-port.sh %(second_port)d %(second_message)s\"")
% {'port': port,
'message': message,
'second_port': nport,
'second_message': second_message})
b.set_val(".containers-run-portmapping form:eq(0) input:eq(1)", port)
b.click(".containers-run-portmapping form:eq(0) .fa-plus")
b.set_val(".containers-run-portmapping form:eq(1) input:eq(0)", nport)
b.set_val(".containers-run-portmapping form:eq(1) input:eq(1)", nport)
# Add a mount point
b.click("#mount-volumes")
b.set_val("#select-mounted-volumes form:eq(0) input:eq(0)", "/blah")
b.set_val("#select-mounted-volumes form:eq(0) input:eq(1)", "/mnt")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
b.wait_in_text("#containers-containers", "PROBE2")
# Check output of the probe
b.click('#containers-containers tr:contains("PROBE2")')
b.wait_in_text("#container-details-ports", ":%d -> %d/tcp" % (port, port))
b.wait_in_text("#container-details-ports", ":%d -> %d/tcp" % (nport, nport))
b.wait_in_text("#container-details-volumes", "/mnt:/blah")
self.wait_for_message(message)
# Check connection on first port, remove trailing whitespace
data = m.execute("exec 3<>/dev/tcp/localhost/%d; cat <&3" % (port)).rstrip()
self.assertEqual(data, message)
self.wait_for_message(second_message)
# Check connection on second port, remove trailing whitespace
data = m.execute("exec 3<>/dev/tcp/localhost/%d; cat <&3" % (nport)).rstrip()
self.assertEqual(data, second_message)
# Wait for exit
b.wait_in_text("#container-details-state", "Exited")
self.del_container_from_details("PROBE2")
def testVolumesAndEnvironment(self):
b = self.browser
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
# Select to view all running containers
b.set_val("#containers-containers-filter", "all")
# Create an updated image, add environment variable
m.execute("mkdir /var/tmp/container-probe")
m.execute("""echo -e '
FROM busybox
ENV zero=GGG
CMD ["/bin/sh"]
' > /var/tmp/container-probe/Dockerfile""")
image_name = "test/container-probe"
m.execute("docker build -t %s /var/tmp/container-probe" % (image_name))
m.execute("rm -rf /var/tmp/container-probe")
# Wait for it to appear
b.wait_in_text("#containers-images", image_name)
# Run it and add another environment variable via the ui
b.click("#containers-images tr:contains(\"%s\") button.fa-play" % (image_name))
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "PROBE4")
b.set_val("#containers-run-image-command", "/bin/sh")
# Two environment variables
b.wait_val("#select-claimed-envvars form:eq(1) input:eq(0)", "zero")
b.wait_val("#select-claimed-envvars form:eq(1) input:eq(1)", "GGG")
b.click("#select-claimed-envvars form:eq(0) .fa-plus")
b.set_val("#select-claimed-envvars form:eq(2) input:eq(0)", "SECOND")
b.set_val("#select-claimed-envvars form:eq(2) input:eq(1)", "marmalade")
# And a mount point
b.click("#mount-volumes")
b.set_val("#select-mounted-volumes form:eq(0) input:eq(0)", "/blah")
b.set_val("#select-mounted-volumes form:eq(0) input:eq(1)", "/mnt")
if m.image not in ["debian-stable", "debian-testing", "ubuntu-1804", "ubuntu-stable"]:
m.execute("chcon --dereference -HRt svirt_sandbox_file_t /mnt")
m.execute("touch /mnt/dripping.txt")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
b.wait_in_text("#containers-containers", "PROBE4")
# Check output of the probe
b.click('#containers-containers tr:contains("PROBE4")')
b.wait_visible("#container-details")
b.wait_present("#container-terminal")
b.wait_present("#container-terminal .console-ct")
b.wait_present("#container-terminal .console-ct .terminal")
b.focus('#container-terminal .console-ct .terminal')
# Wait for the container to wake up
try:
b.key_press("\r\r\r")
b.wait_in_text("#container-terminal", "#")
except Error as ex:
if not ex.msg.startswith('timeout'):
raise
b.key_press("clear\r")
b.wait_in_text("#container-terminal", "#")
b.focus('#container-terminal .console-ct .terminal')
b.key_press("env\r")
b.wait_in_text("#container-terminal", "zero=GGG")
b.wait_in_text("#container-terminal", "SECOND=marmalade")
b.focus('#container-terminal .console-ct .terminal')
b.key_press("ls /blah/\r")
b.wait_in_text("#container-terminal", "dripping.txt")
self.allow_journal_messages('.*denied.*name_connect.*docker.*')
@skipImage("No cockpit-docker on i386", "fedora-i386")
def testFailure(self):
b = self.browser
m = self.machine
# Try to access docker without admin (wheel, sudo, ...) group
# also need to disable Ubuntu's legacy "admin" sudo group as it happens
# to have the same name as our admin test user
m.execute("usermod -G '' admin; sed -i '/^%admin/d' /etc/sudoers")
self.allow_journal_messages("http:///var/run/docker.sock/.*: couldn't connect: .*")
self.login_and_go("/docker", authorized=False)
# We can not become root, so we can't access docker.
b.wait_text("#curtain h1", "Not authorized to access Docker on this system")
b.wait_visible("#curtain button[data-action='docker-connect']")
# Give "admin" access via the admin group and login again
m.execute("usermod -G %s admin" % m.get_admin_group())
m.execute("systemctl stop docker")
b.relogin("/docker", authorized=True)
self.allow_restart_journal_messages()
# Now we can become root and start docker
b.wait_text("#curtain h1", "Docker is not installed or activated on the system")
b.click("#curtain button[data-action='docker-start']")
with b.wait_timeout(120):
b.wait_visible("#containers-containers")
self.allow_authorize_journal_messages()
self.allow_journal_messages("cannot reauthorize identity.*:.*unix-user:root.*")
self.allow_journal_messages("cannot reauthorize identity.*:.*unix-user:builder.*")
def testRestart(self):
b = self.browser
m = self.machine
# This happens due to the Docker restart
self.allow_journal_messages('.*received truncated HTTP response.*')
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
# Run one container without restarting
b.wait_visible("#containers-images")
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "NORESTART")
b.set_val("#containers-run-image-command", "/bin/sh -c 'echo \"no-restart\"; sleep 10000'")
b.click("#containers-run-image-with-terminal")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
# Run another container with restarting
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "YAYRESTART")
b.set_val("#containers-run-image-command", "/bin/sh -c 'echo \"yay-restart\"; sleep 10000'")
b.click("#containers-run-image-with-terminal")
b.click("#restart-policy-select button")
b.click("#restart-policy-select a[data-value=always]")
b.wait_in_text("#restart-policy-select button", "Always")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
# Make sure they've started
b.wait_in_text("#containers-containers", "NORESTART")
b.wait_in_text("#containers-containers", "YAYRESTART")
# Restart docker, docker.socket needs special handling
b.logout()
m.execute("(systemctl kill --signal=9 docker-containerd && systemctl restart docker-containerd ) || systemctl restart docker || systemctl restart docker-latest")
self.login_and_go("/docker")
# show all containers to interact with stopped ones
with b.wait_timeout(120):
b.wait_visible("#containers-containers")
b.set_val("#containers-containers-filter", "all")
# Now check that one restarts
b.wait_in_text("#containers-images", "busybox:latest")
b.wait_present('#containers-containers tr:contains("YAYRESTART") td:contains("running")')
b.wait_present('#containers-containers tr:contains("NORESTART") td:contains("exited")')
def testResources(self):
b = self.browser
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
self.login_and_go("/docker")
b.wait_in_text("#containers-images", "busybox:latest")
# Run one container without restarting
b.click('#containers-images tr:contains("busybox:latest") button.fa-play')
b.wait_popup("containers_run_image_dialog")
b.set_val("#containers-run-image-name", "RESOURCE")
b.set_val("#containers-run-image-command", "/bin/sleep 1000000")
b.click("#containers-run-image-with-terminal")
b.click("#containers-run-image-memory input[type='checkbox']")
b.set_val("#containers-run-image-memory input.size-text-ct", "236")
b.click("#containers-run-image-cpu input[type='checkbox']")
b.set_val("#containers-run-image-cpu input.size-text-ct", "512")
b.click("#containers-run-image-run")
b.wait_popdown("containers_run_image_dialog")
# Make sure they've started
b.wait_in_text("#containers-containers", "RESOURCE")
# Check output of PROBE1
b.click('#containers-containers tr:contains("RESOURCE")')
b.wait_in_text("#container-details-memory-row", "/ 236 MiB")
b.wait_in_text("#container-details-cpu-row", "512 shares")
# Now adjust things
b.click("#container-details-resource-row button")
b.wait_popup("container-resources-dialog")
b.set_val(".memory-slider input.size-text-ct", "246")
b.set_val(".cpu-slider input.size-text-ct", "256")
b.click("#container-resources-dialog .btn-primary")
b.wait_popdown("container-resources-dialog")
# This should be updated
b.wait_in_text("#container-details-memory-row", "/ 246")
b.wait_in_text("#container-details-cpu-row", "256 shares")
# Remove the restrictions
b.click("#container-details-resource-row button")
b.wait_popup("container-resources-dialog")
b.click(".memory-slider input[type='checkbox']")
b.click(".cpu-slider input[type='checkbox']")
b.click("#container-resources-dialog .btn-primary")
b.wait_popdown("container-resources-dialog")
# This should be updated
b.wait_in_text("#container-details-cpu-row", "1024 shares")
@skipImage("No cockpit-docker on i386", "fedora-i386")
@skipImage("ABRT not available", "debian-stable", "debian-testing", "ubuntu-stable",
"ubuntu-1804", "rhel-8-1", "rhel-8-1-distropkg", "rhel-8-2")
def testContainerProblems(self):
b = self.browser
m = self.machine
m.execute("systemctl start docker || systemctl start docker-latest")
# start container
m.execute('docker run -dit --name crashing_container busybox /bin/sh')
# crash in container
m.execute('docker exec crashing_container sh -c "sleep 5 & sleep 1; pkill -ABRT sleep"')
self.allow_journal_messages('Process.*sleep.*dumped core.*')
self.allow_journal_messages('Stack trace.*')
self.allow_journal_messages('#0.*sleep.*')
# login and go to docker page (Docker Containers)
self.login_and_go("/docker")
sel = "#containers-containers .listing-ct-item .listing-ct-toggle"
b.click(sel)
# wait for the Problems tab then click it
sel = '#containers-containers .listing-ct-panel .listing-ct-head ul li a:contains("Problems")'
b.click(sel)
# open link to logs
sel = "#containers-containers .listing-ct-panel .listing-ct-body a.list-group-item"
b.wait_in_text(sel, "sleep")
b.click(sel + ':contains("sleep")')
# wait for the page to load
b.enter_page("/system/logs")
# check for abrtd service in text
b.wait_in_text("#journal-entry-heading", "sleep")
b.wait_in_text("#journal-entry-fields", "abrtd.service")
@skipImage("Skip on systems without atomic and ones with missing deps", "debian-stable",
"debian-testing", "ubuntu-1804", "ubuntu-stable", "fedora-coreos", "fedora-i386",
"fedora-31")
@skipImage("No docker packaged", "rhel-8-1", "rhel-8-1-distropkg", "rhel-8-2")
@skipPackage("cockpit-docker")
class TestAtomicScan(MachineCase):
def setUp(self):
MachineCase.setUp(self)
self.machine.execute("systemctl start docker")
def testBasic(self):
b = self.browser
m = self.machine
# HACK put scan results for one of the images into /var/lib/atomic
#
# This mimics what `atomic scan` would put there, without us having to install
# a known vulnerable image and initiating a scan from this test.
infos = json.loads(m.execute("docker inspect busybox"))
image_id = infos[0]["Id"]
short_id = image_id.replace("sha256:", "")
result_path = os.path.join("/var/lib/atomic/atomic_scan_openscap/2016-12-11-12-09-57-674487/", short_id)
result_filename = os.path.join(result_path, "json")
scan_summary = {
short_id: {
"Scan Type": "Standards Compliance",
"json_file": result_filename,
"Scanner": "openscap",
"Time": "2016-12-11T12:09:59",
"Vulnerable": True,
"UUID": short_id
}
}
scan_result = {
"Scanner": "openscap",
"Vulnerabilities": [
{
"Description": "\nThe RPM package management system can check file access\npermissions of installed software packages, including many that are\nimportant to system security. \nAfter locating a file with incorrect permissions, run the following command to determine which package owns it:\n",
"Title": "Verify and Correct File Permissions with RPM",
"Custom": {
"XCCDF result": "fail"
},
"Severity": "Low"
},
{
"Description": "\nSystem executables are stored in the following directories by default:\n",
"Title": "Verify that System Executables Have Restrictive Permissions",
"Custom": {
"XCCDF result": "fail"
},
"Severity": "Moderate"
}
],
"Finished Time": "2016-12-11T12:10:27",
"UUID": "/scanin/d6fe5fdc49c2886ccad1c781d38a0c9fe679c6e7ca0297d23186c385873e86fa",
"Scan Type": "Standard Compliance",
"Time": "2016-12-11T12:09:59",
"Successful": "true"
}
m.execute("mkdir -p " + result_path)
m.execute("echo '%s' > /var/lib/atomic/scan_summary.json" % json.dumps(scan_summary))
m.execute("echo '%s' > %s" % (json.dumps(scan_result), result_filename))
self.login_and_go("/docker")
row_selector = '#containers-images tr[data-row-id="%s"]' % image_id
# warning badge should exist
b.wait_present(row_selector + ' td span.pficon-warning-triangle-o')
b.wait_visible(row_selector + ' td span.pficon-warning-triangle-o')
# Security tab should exist
b.click(row_selector + ' td.listing-ct-toggle')
b.wait_visible(row_selector + ' + tr a:contains("Security")')
b.click(row_selector + ' + tr a:contains("Security")')
b.wait_in_text(row_selector + ' + tr', 'Verify and Correct File Permissions with RPM')
# Collapse the tab and click through to the image
b.click(row_selector + ' td.listing-ct-toggle')
b.click(row_selector + ' th')
b.wait_in_text("#image-details", "Security")
b.wait_in_text("#image-details", "Verify and Correct File Permissions with RPM")
if __name__ == '__main__':
test_main()