Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Changelog
1.3.0 (not yet released)
~~~~~~~~~~~~~~~~~~~~~~~~

New features
------------

+ `#25`_, `#30`_: add a `auto_agree_with_licenses` configuration flag.

Behavioral change
-----------------

Expand All @@ -19,10 +24,12 @@ Internal
+ `#26`_, `#27`_, `#29`_: review test suite.

.. _#24: https://github.com/RKrahl/auto-patch/issues/24
.. _#25: https://github.com/RKrahl/auto-patch/issues/25
.. _#26: https://github.com/RKrahl/auto-patch/pull/26
.. _#27: https://github.com/RKrahl/auto-patch/pull/27
.. _#28: https://github.com/RKrahl/auto-patch/pull/28
.. _#29: https://github.com/RKrahl/auto-patch/pull/29
.. _#30: https://github.com/RKrahl/auto-patch/pull/30


.. _changes-1_2_0:
Expand Down
6 changes: 6 additions & 0 deletions etc/auto-patch.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
# The configuration values below are the default values commented out
# by a leading '!'.

[zypper]
# Configuration for the zypper call. The /auto_agree_with_licenses/
# flag controls whether or not to add the `--auto-agree-with-licenses`
# flag to the `zypper patch` call.
!auto_agree_with_licenses = no

[mailreport]
# A mail report may be sent if patches are available or have been
# installed. This is controlled by the /report/ flag, default is on.
Expand Down
5 changes: 5 additions & 0 deletions scripts/auto-patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
config_files = "/etc/auto-patch.cfg"

config_defaults = {
'zypper': {
'auto_agree_with_licenses': "no",
},
'mailreport': {
'report': "on",
'hostname': socket.getfqdn(),
Expand Down Expand Up @@ -250,6 +253,8 @@ def patch(self, stdout=None):
args = ["--quiet", "--non-interactive", "patch", "--skip-interactive"]
if self.version >= Version("1.14.69"):
args.append("--skip-not-applicable-patches")
if config['zypper'].getboolean('auto_agree_with_licenses'):
args.append("--auto-agree-with-licenses")
return self.call(args, stdout=stdout)

def ps(self, stdout=None):
Expand Down
3 changes: 2 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def get_zypper_argument_parser():
parser.add_argument('subcmd', nargs='?')
parser.add_argument('--skip-interactive', action='store_true')
parser.add_argument('--skip-not-applicable-patches', action='store_true')
parser.add_argument('--auto-agree-with-licenses', action='store_true')
return parser

zypper_arg_parser = get_zypper_argument_parser()
Expand Down Expand Up @@ -133,7 +134,7 @@ def get_caller(cls, case, config=None):
return cls(zypper_results, config)

def _create_config(self, config):
d = { 'mailreport': {}, 'retry': {}, 'logging': {} }
d = { 'zypper': {}, 'mailreport': {}, 'retry': {}, 'logging': {} }
if config is not None:
for k in config.keys():
d[k].update(config[k])
Expand Down
13 changes: 0 additions & 13 deletions tests/test_02_exitcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,3 @@ def test_error_scripterr(tmpdir):
caller = AutoPatchCaller.get_caller("err_scripterr")
caller.run(exitcode=107)
caller.check_report(extra_msg="ERROR:")


def test_error_license(tmpdir):
"""Patch fails due to missing license confirmation.

A patch for a non-free package requires agreement with the terms
of the license, which doesn't work in non-interactive mode. The
patch command fails with ZypperLibraryError.
"""
with tmpdir.as_cwd():
caller = AutoPatchCaller.get_caller("no_license_consent")
caller.run(exitcode=4)
caller.check_report(extra_msg="ERROR:")
50 changes: 50 additions & 0 deletions tests/test_02_licenses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Special case: a patch requires accepting a third party license.

A patch for a non-free package requires agreement with the terms of
the license. By default, the zypper patch call fails with
ZypperLibraryError in non-interactive mode. This can either be fixed
by manual intervention by the admin or by setting the
auto_agree_with_licenses configuration flag to yes.
"""

import pytest
from conftest import AutoPatchCaller


def test_license_default(tmpdir):
"""Default configuration.

The patch command fails with ZypperLibraryError.
"""
with tmpdir.as_cwd():
caller = AutoPatchCaller.get_caller("no_license_consent")
caller.run(exitcode=4)
caller.check_report(extra_msg="ERROR:")


@pytest.mark.parametrize("flag", ["0", "no", "false", "off"])
def test_license_auto_agree_no(tmpdir, flag):
"""Explicitely switch off auto_agree_with_licenses.

This is the default, so we won't get any different behavior.
Try out different representations of the negative value.
"""
with tmpdir.as_cwd():
cfg = { 'zypper': {'auto_agree_with_licenses': flag} }
caller = AutoPatchCaller.get_caller("no_license_consent", config=cfg)
caller.run(exitcode=4)
caller.check_report(extra_msg="ERROR:")


@pytest.mark.parametrize("flag", ["1", "yes", "true", "on"])
def test_license_auto_agree_yes(tmpdir, flag):
"""Explicitely switch on auto_agree_with_licenses.

In this case, the patch is applied successfully.
Try out different representations of the affirmative value.
"""
with tmpdir.as_cwd():
cfg = { 'zypper': {'auto_agree_with_licenses': flag} }
caller = AutoPatchCaller.get_caller("auto_license_consent", config=cfg)
caller.run()
caller.check_report()
35 changes: 35 additions & 0 deletions tests/zypper-result-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -713,5 +713,40 @@
"--skip-not-applicable-patches"
]
}
],
"auto_license_consent": [
{
"cmd": null,
"stdout": "zypper 1.14.94",
"capture": false
},
{
"cmd": "patch-check",
"returncode": 100,
"stdout": "\nCategory | Patches\n------------+--------\nrecommended | 1\n\n1 patch needed (0 security patches)\n"
},
{
"cmd": "list-patches",
"stdout": "\nRepository | Name | Category | Severity | Interactive | Status | Summary\n-------------------------------------------------------------+-----------------------------+-------------+----------+-------------+--------+-----------------------------------------------------\nUpdate repository with updates from SUSE Linux Enterprise 15 | openSUSE-SLE-15.6-2026-1084 | recommended | moderate | --- | needed | Recommended update for nvidia-open-driver-G06-signed\n\n1 patch needed (0 security patches)\n"
},
{
"cmd": "patch",
"stdout": "\nThe following 10 packages are going to be upgraded:\n libnvidia-gpucomp nvidia-common-G06 nvidia-compute-G06 nvidia-compute-utils-G06 nvidia-gl-G06 nvidia-modprobe nvidia-open-driver-G06-signed-kmp-meta nvidia-persistenced nvidia-userspace-meta-G06 nvidia-video-G06\n\nThe following NEW package is going to be installed:\n nvidia-open-driver-G06-signed-kmp-default-580.126.18_k6.4.0_150600.23.87-150600.3.85.1\n\nThe following NEW patch is going to be installed:\n openSUSE-SLE-15.6-2026-1084\n\nThe following package is going to be REMOVED:\n nvidia-open-driver-G06-signed-kmp-default-580.126.09_k6.4.0_150600.23.81-150600.3.80.1\n\n10 packages to upgrade, 1 new, 1 to remove.\n\nPackage download size: 294.3 MiB\n\nPackage install size change:\n | 997.5 MiB required by packages that will be installed\n 12.9 KiB | - 997.5 MiB released by packages that will be removed\n\nBackend: classic_rpmtrans\nContinue? [y/n/v/...? shows all options] (y): y\n",
"args": [
"--quiet",
"--non-interactive",
"patch",
"--skip-interactive",
"--skip-not-applicable-patches",
"--auto-agree-with-licenses"
]
},
{
"cmd": "patch-check",
"stdout": "\n0 patches needed (0 security patches)\n"
},
{
"cmd": "ps"
}
]
}