Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-osc-tiny for openSUSE:Factory
checked in at 2023-01-02 15:02:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
and /work/SRC/openSUSE:Factory/.python-osc-tiny.new.1563 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-osc-tiny"
Mon Jan 2 15:02:27 2023 rev:26 rq:1046130 version:0.7.10
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes
2022-12-13 18:55:41.899277236 +0100
+++
/work/SRC/openSUSE:Factory/.python-osc-tiny.new.1563/python-osc-tiny.changes
2023-01-02 15:02:34.193486341 +0100
@@ -1,0 +2,9 @@
+Mon Jan 2 09:33:59 UTC 2023 - Andreas Hasenkopf <[email protected]>
+
+- Release 0.7.10
+ * Include the original error message, when an SSH key cannot be read
+ * Added a link to the documentation of `HttpSignatureAuth`
+ * Allow `Package.exists` to raise exceptions
+ * Added methods to get/set the project config
+
+-------------------------------------------------------------------
Old:
----
osc-tiny-0.7.9.tar.gz
New:
----
osc-tiny-0.7.10.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.IFYKUS/_old 2023-01-02 15:02:34.857490072 +0100
+++ /var/tmp/diff_new_pack.IFYKUS/_new 2023-01-02 15:02:34.861490095 +0100
@@ -18,7 +18,7 @@
%define skip_python2 1
Name: python-osc-tiny
-Version: 0.7.9
+Version: 0.7.10
Release: 0
Summary: Client API for openSUSE BuildService
License: MIT
++++++ osc-tiny-0.7.9.tar.gz -> osc-tiny-0.7.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/PKG-INFO new/osc-tiny-0.7.10/PKG-INFO
--- old/osc-tiny-0.7.9/PKG-INFO 2022-12-12 13:21:46.650442600 +0100
+++ new/osc-tiny-0.7.10/PKG-INFO 2023-01-02 10:27:08.909208300 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.7.9
+Version: 0.7.10
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osc_tiny.egg-info/PKG-INFO
new/osc-tiny-0.7.10/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.7.9/osc_tiny.egg-info/PKG-INFO 2022-12-12
13:21:46.000000000 +0100
+++ new/osc-tiny-0.7.10/osc_tiny.egg-info/PKG-INFO 2023-01-02
10:27:08.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.7.9
+Version: 0.7.10
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/__init__.py
new/osc-tiny-0.7.10/osctiny/__init__.py
--- old/osc-tiny-0.7.9/osctiny/__init__.py 2022-12-12 13:21:36.000000000
+0100
+++ new/osc-tiny-0.7.10/osctiny/__init__.py 2023-01-02 10:26:59.000000000
+0100
@@ -6,4 +6,4 @@
__all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
'projects', 'search', 'users']
-__version__ = "0.7.9"
+__version__ = "0.7.10"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/extensions/packages.py
new/osc-tiny-0.7.10/osctiny/extensions/packages.py
--- old/osc-tiny-0.7.9/osctiny/extensions/packages.py 2022-12-12
13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/osctiny/extensions/packages.py 2023-01-02
10:26:59.000000000 +0100
@@ -470,7 +470,7 @@
return parsed
- def exists(self, project, package, filename=None):
+ def exists(self, project, package, filename=None) -> bool:
"""
Check whether package or file in package exists
@@ -493,6 +493,12 @@
raise_for_status=False
)
+ if response.status_code == 404:
+ return False
+
+ # 404 is the only acceptable HTTP error code, otherwise raise an
exception
+ response.raise_for_status()
+
return response.status_code == 200
# pylint: disable=too-many-locals
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/extensions/projects.py
new/osc-tiny-0.7.10/osctiny/extensions/projects.py
--- old/osc-tiny-0.7.9/osctiny/extensions/projects.py 2022-12-12
13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/osctiny/extensions/projects.py 2023-01-02
10:26:59.000000000 +0100
@@ -358,6 +358,55 @@
return self.osc.get_objectified_xml(response)
+ def get_config(self, project, revision=None):
+ """
+ Get project configuration
+
+ .. versionadded:: 0.7.10
+
+ :param project: name of project
+ :param revision: optional revision of the config to get
+ :return: The project configuration as string
+ :rtype: str
+ """
+ response = self.osc.request(
+ url=urljoin(
+ self.osc.url,
+ "{}/{}/_config".format(self.base_path, project)
+ ),
+ params={"rev":revision},
+ method="GET"
+ )
+
+ return response.text
+
+ def set_config(self, project, config=None, comment=None):
+ """
+ Set project config data
+
+ .. versionadded:: 0.7.10
+
+ :param project: name of project
+ :param config: Complete configuration to set
+ :type config: str
+ :param comment: Optional comment to use as commit message
+ :return: ``True``, if successful. Otherwise, API response
+ :rtype: bool or lxml.objectify.ObjectifiedElement
+ """
+ response = self.osc.request(
+ url=urljoin(self.osc.url,
+ "/".join((self.base_path, project, "_config"))),
+ method="PUT",
+ data=config,
+ params={"comment": comment}
+ )
+
+ parsed = self.osc.get_objectified_xml(response)
+ if response.status_code == 200 and parsed.get("code") == "ok":
+ return True
+
+ return parsed
+
def delete(self, project, force=False, comment=None):
"""
Delete project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/tests/test_packages.py
new/osc-tiny-0.7.10/osctiny/tests/test_packages.py
--- old/osc-tiny-0.7.9/osctiny/tests/test_packages.py 2022-12-12
13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/osctiny/tests/test_packages.py 2023-01-02
10:26:59.000000000 +0100
@@ -3,6 +3,7 @@
import re
from unittest import skip
+from requests import HTTPError
import responses
from .base import OscTest, CallbackFactory
@@ -520,3 +521,30 @@
self.assertEqual(expected,
self.osc.packages.cleanup_params(view="verboseproductlist",
expand=True))
+
+ @responses.activate
+ def test_exists(self):
+ data = (
+ # status, expected
+ (200, True),
+ (404, False),
+ (401, None),
+ (500, None)
+ )
+
+ def callback(headers, params, request):
+ return status, headers, ""
+
+ self.mock_request(
+ method=responses.HEAD,
+ url=re.compile(self.osc.url + '/source/.+'),
+ callback=CallbackFactory(callback)
+ )
+
+ for status, expected in data:
+ with self.subTest(status):
+ if expected is not None:
+ self.assertEqual(expected,
self.osc.packages.exists("Some:Project", "package"))
+ else:
+ self.assertRaises(HTTPError, self.osc.packages.exists,
"Some:Project",
+ "package")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/tests/test_projects.py
new/osc-tiny-0.7.10/osctiny/tests/test_projects.py
--- old/osc-tiny-0.7.9/osctiny/tests/test_projects.py 2022-12-12
13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/osctiny/tests/test_projects.py 2023-01-02
10:26:59.000000000 +0100
@@ -370,6 +370,80 @@
)
@responses.activate
+ def test_get_config(self):
+ def callback(headers, params, request):
+ status = 200
+ body = "the_config"
+ self.assertTrue("/_config" in request.url)
+ if "Devel:ARM:Factory" not in request.url:
+ status = 404
+ body = """
+ <status code="unknown_project">
+ <summary>Devel:ARM:Fbctory</summary>
+ </status>
+ """
+ headers['request-id'] = '728d329e-0e86-11e4-a748-0c84dc037c13'
+ return status, headers, body
+
+ self.mock_request(
+ method=responses.GET,
+ url=re.compile(self.osc.url + '/source/.*'),
+ callback=CallbackFactory(callback)
+ )
+
+ with self.subTest("existing project"):
+ response = self.osc.projects.get_config("Devel:ARM:Factory")
+ self.assertEqual(response, "the_config")
+
+ with self.subTest("non-existing project"):
+ self.assertRaises(
+ HTTPError, self.osc.projects.get_config, "Devel:ARM:Fbctory"
+ )
+
+ with self.subTest("existing project with revision"):
+ response = self.osc.projects.get_config("Devel:ARM:Factory",
revision=3)
+ self.assertEqual(response, "the_config")
+ self.assertEqual(responses.calls[-1].request.params["rev"], "3")
+
+ @responses.activate
+ def test_set_config(self):
+ def callback(headers, params, request):
+ status = 500
+ body = "<status code='error'></status>"
+ match = re.search("source/(?P<project>[^/]+)/_config", request.url)
+ if match and not "invalid" in request.url:
+ status = 200
+ body = """<status code='ok'></status>"""
+
+ headers['request-id'] = '728d329e-0e86-11e4-a748-0c84dc037c13'
+ return status, headers, body
+
+ self.mock_request(
+ method=responses.PUT,
+ url=re.compile(self.osc.url + '/source/[^/]+/_config'),
+ callback=CallbackFactory(callback)
+ )
+
+ with self.subTest("Valid request"):
+ self.assertTrue(self.osc.projects.set_config(
+ project="test",
+ config="foo bar",
+ ))
+
+ with self.subTest("Invalid request"):
+ self.assertRaises(
+ HTTPError,
+ self.osc.projects.set_config,
+ project="invalid:project",
+ config="test_config"
+ )
+
+ with self.subTest("Valid request with comment"):
+
self.assertTrue(self.osc.projects.set_config(project="project:foo",
config="test conf",
+ comment="Test"))
+ self.assertEqual(responses.calls[-1].request.params["comment"],
"Test")
+
+ @responses.activate
def test_delete(self):
def callback(headers, params, request):
if "existing" in request.url:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/tests/test_utils.py
new/osc-tiny-0.7.10/osctiny/tests/test_utils.py
--- old/osc-tiny-0.7.9/osctiny/tests/test_utils.py 2022-12-12
13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/osctiny/tests/test_utils.py 2023-01-02
10:26:59.000000000 +0100
@@ -396,7 +396,7 @@
@mock.patch("osctiny.utils.auth.time", return_value=123456)
class TestAuth(TestCase):
- @mock.patch("osctiny.utils.auth.is_ssh_key_readable", return_value=True)
+ @mock.patch("osctiny.utils.auth.is_ssh_key_readable", return_value=(True,
None))
def setUp(self, *_):
super().setUp()
mocked_path = mock.MagicMock(spec=Path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/osctiny/utils/auth.py
new/osc-tiny-0.7.10/osctiny/utils/auth.py
--- old/osc-tiny-0.7.9/osctiny/utils/auth.py 2022-12-12 13:21:36.000000000
+0100
+++ new/osc-tiny-0.7.10/osctiny/utils/auth.py 2023-01-02 10:26:59.000000000
+0100
@@ -54,7 +54,8 @@
return None
-def is_ssh_key_readable(ssh_key_file: Path, password: typing.Optional[str]) ->
bool:
+def is_ssh_key_readable(ssh_key_file: Path, password: typing.Optional[str]) \
+ -> typing.Tuple[bool, typing.Optional[str]]:
"""
Check whether SSH key can be read/unlocked
@@ -67,17 +68,21 @@
.. versionchanged:: 0.7.8
* Moved from ``HttpSignatureAuth.is_ssh_agent_available``
+
+ .. versionchanged:: 0.7.10
+
+ * Return the error message, if key cannot be unlocked
"""
cmd = ['ssh-keygen', '-y', '-f', ssh_key_file.as_posix()]
if password:
cmd += ['-P', password]
- with Popen(cmd, stdin=DEVNULL, stderr=DEVNULL, stdout=DEVNULL) as proc:
- proc.communicate()
+ with Popen(cmd, stdin=DEVNULL, stderr=PIPE, stdout=DEVNULL) as proc:
+ _, error = proc.communicate()
if proc.returncode == 0:
- return True
+ return True, None
- return False
+ return False, error.decode("utf-8") if isinstance(error, bytes) else error
class HttpSignatureAuth(HTTPDigestAuth):
@@ -88,13 +93,16 @@
This seems to be a variation of the `HTTP Message Signatures`_
specification.
- See also the `reference implementation for osc`_
+ See also the `blog post`_ describing the implementation and the
+ `reference implementation for osc`_.
.. _HTTP Message Signatures:
https://datatracker.ietf.org/doc/draft-ietf-httpbis-message-signatures/
.. _reference implementation for osc:
https://github.com/openSUSE/osc/pull/1032
+ .. _blog post:
https://www.suse.com/c/multi-factor-authentication-on-suses-build-service/
+
.. note::
1. It is recommended to use SSH keys with a passphrase.
@@ -110,8 +118,9 @@
super().__init__(username=username, password=password)
if not ssh_key_file.is_file():
raise FileNotFoundError(f"SSH key at location does not exist:
{ssh_key_file}")
- if not is_ssh_key_readable(ssh_key_file=ssh_key_file,
password=password):
- raise RuntimeError("SSH signing impossible: Unable to decrypt
key.")
+ readable, error = is_ssh_key_readable(ssh_key_file=ssh_key_file,
password=password)
+ if not readable:
+ raise RuntimeError(f"SSH signing impossible because key cannot be
decrypted: {error}.")
self.ssh_key_file = ssh_key_file
self.pattern = re.compile(r"(?<=\)) (?=\()")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.7.9/setup.py new/osc-tiny-0.7.10/setup.py
--- old/osc-tiny-0.7.9/setup.py 2022-12-12 13:21:36.000000000 +0100
+++ new/osc-tiny-0.7.10/setup.py 2023-01-02 10:26:59.000000000 +0100
@@ -26,7 +26,7 @@
setup(
name='osc-tiny',
- version='0.7.9',
+ version='0.7.10',
description='Client API for openSUSE BuildService',
long_description=long_description,
long_description_content_type="text/markdown",