-
-
Notifications
You must be signed in to change notification settings - Fork 387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow setting git opt set sll cert locations option in libgit2 #879
Allow setting git opt set sll cert locations option in libgit2 #879
Conversation
Oh, I missed this PR... P.S. s/sll/ssl/ in title |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've pointed out a few anti-pythonic approaches which should be fixed: pygit2 is a Python wrapper and as such, it shouldn't 100% repeat C-library principles on the high level.
@@ -28,6 +28,9 @@ | |||
# Import from the future | |||
from __future__ import absolute_import | |||
|
|||
# Import from core python modules | |||
from ssl import get_default_verify_paths as default_ssl_verify_paths |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't rename this callable. It's an action, not a constant. So I must start with a verb. get
. Renaming it to constant/var-style is harmful and misleading for readability.
from ssl import get_default_verify_paths as default_ssl_verify_paths | |
from ssl import get_default_verify_paths |
try: | ||
# try to set default ssl cert locations | ||
settings._ssl_cert_locations = default_ssl_verify_paths() | ||
except: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't catch all exceptions. Silencing everything makes any related bugs nearly impossible to locate and is harmful therefore. It's important to always fail fast and loudly.
ssl.get_default_verify_paths()
shouldn't raise any exceptions anyway.
except: |
""" | ||
return option(GIT_OPT_SET_SSL_CERT_LOCATIONS, value, None) | ||
|
||
ssl_cert_file = property(fset=__set_ssl_cert_file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is an ancient way of creating properties. Always use it as a decorator instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we should have a getter for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no get support for the ssl cert paths in libgit2
. It makes sense to have it added to libgit2
first.
You can not use property
as decorator if you don't have a setter since the first param in the __init__
for property
is fget
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But you can track it on the Python side because it's needed to properly set the other value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can still use a decorator:
@property
def attr(self):
"""A proper docstring."""
raise AttributeError
@attr.setter
def attr(self, value):
# set val
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here's why we need to track the values we set earlier. Semantically, these setters are assigned with the values for what their names mean.
End-users of the library are Pythonistas who always expect the assignment behavior of the attribute to change exactly the thing its name refers to.
So resetting another setting would be misleading and is a side-effect.
That's why we need to track values which we set earlier for one connected setting to use them when setting the other.
Of course, it's not necessary to expose them for reading right now. But it's a least we can do to preserve consistent UX when setting one of TSL cert location sub-options.
As for setting both sub-options, it should be an explicit method because semantically setting a tuple to attribute to side-effect two values is weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Digging around, it looks like ultimately libgit2
makes a call to SSL_CTX_load_verify_locations
when built with Openssl and the man page for it seems to describe the following behavior.
When looking up CA certificates, the OpenSSL library will first search the certificates in CAfile, then those in CApath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, that's what I thought...
def __set_ssl_cert_file(self, value): | ||
"""Set the ssl cert file. The value cannot be read. | ||
""" | ||
return option(GIT_OPT_SET_SSL_CERT_LOCATIONS, value, None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setters don't return values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When setting one value we shouldn't reset another. If a user wants to do this they can update it to None
explicitly.
@@ -101,4 +101,30 @@ def cache_object_limit(self, object_type, value): | |||
""" | |||
return option(GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, value) | |||
|
|||
def __set_ssl_cert_file(self, value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def __set_ssl_cert_file(self, value): | |
@property | |
def ssl_cert_file(self): | |
return self._ssl_cert_file | |
@ssl_cert_file.setter | |
def ssl_cert_file(self, value): | |
"""Set the ssl cert file.""" | |
option(GIT_OPT_SET_SSL_CERT_LOCATIONS, value, self.ssl_cert_dir) | |
self._ssl_cert_file = value |
|
||
ssl_cert_dir = property(fset=__set_ssl_cert_dir) | ||
|
||
def __set_ssl_cert_locations(self, locations): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one must be a method. Using property here is odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with properties because all other supported settings are implemented as property. It does not make sense to break consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I wrote earlier, we should go for Pythonic principles. And if they are not respected in some places it doesn't mean that you should follow the lead. When you write in C you don't follow Assembly code-style just because it's an underlying somewhere, do you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look at the issues this week-end.
But generally speaking, from PEP-8 itself:
Consistency with this style guide is important. Consistency within a project is more important.
Though we don't have a project style guide. Well, will check this week-end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole paragraph:
A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, thank you both for the awesome work you're doing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rule doesn't apply here. Since all other attributes correspond to one value. With two values it doesn't make sense. Setting two values by assigning a tuple to an attribute is ridiculous in Python.
And also when writing Python it doesn't have to look like another language https://www.youtube.com/watch?v=wf-BqAjZb8M. It's fine in the low-level wrapper but not in a public interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I wasn't referring to just PEP8. It's quite a common sense/knowledge. PEP8 is a code style guide but I'm talking about more generic approaches which are probably not formalized explicitly but every Pythonista knows that when they see code looking like Java in .py
file something isn't quite right.
|
||
try: | ||
# try to set default ssl cert locations | ||
settings._ssl_cert_locations = default_ssl_verify_paths() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this belongs at Settings.__init__()
. It is a good practice to have a ready-to-use object after the initializer run.
Extra initializers are popular in C++, not Python. This semantics is untypical for Pythonic projects.
I still think that setting one value shouldn't reset another one. |
Finally looked at the api. I would replace both setters by a single method:
|
I'd keep properties for individual suboptions. They are native to Python and is what a typical Pythonista would expect. It better communicates the intent as in "make this setting use that value". |
I'd rather not have 2 ways to do the same thing. It's good for the users to have 1 way, so they don't have to stop thinking which one they should use, and code looks the same whoever writes it. It's also good for the developers/maintainers not to increase the burden: our limited resources are the main constraint. Aiming for feature completeness, api consistency, and quality documentation is already ambitious. So I'd keep it simple and stick to the 1 way principle (even if the API feels a bit low level, it's not awkward either). The Then the |
Yes, there should be one way of doing things. Except for the cases where that way cannot be used. So are you okay with property-based getters/setters then? |
Could you summarize the API you propose for ssl cert locations? |
I'll send it as a PR on top of this branch |
Side note: after looking at |
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Usage:: import pygit2 pygit2.settings.ssl_cert_file = '/path/to/file' pygit2.settings.ssl_cert_dir = '/path/to/folder' del pygit2.settings.ssl_cert_file pygit2.settings.set_ssl_cert_locations( '/path/to/new/file', '/path/to/new/folder', ) Co-authored-by: Sriram Raghu <[email protected]> Closes libgit2#876 Superseeds and closes libgit2#879
Add test target. 0.28.0 (2019-03-19) ------------------------- - Upgrade to libgit2 0.28 `#878 <https://github.com/libgit2/pygit2/issues/878>`_ - Add binary wheels for Linux `#793 <https://github.com/libgit2/pygit2/issues/793>`_ `#869 <https://github.com/libgit2/pygit2/pull/869>`_ `#874 <https://github.com/libgit2/pygit2/pull/874>`_ `#875 <https://github.com/libgit2/pygit2/pull/875>`_ `#883 <https://github.com/libgit2/pygit2/pull/883>`_ - New ``pygit2.Mailmap``, see documentation `#804 <https://github.com/libgit2/pygit2/pull/804>`_ - New ``Repository.apply(...)`` wraps ``git_apply(..)`` `#841 <https://github.com/libgit2/pygit2/issues/841>`_ `#843 <https://github.com/libgit2/pygit2/pull/843>`_ - Now ``Repository.merge_analysis(...)`` accepts an optional reference parameter `#888 <https://github.com/libgit2/pygit2/pull/888>`_ `#891 <https://github.com/libgit2/pygit2/pull/891>`_ - Now ``Repository.add_worktree(...)`` accepts an optional reference parameter `#814 <https://github.com/libgit2/pygit2/issues/814>`_ `#889 <https://github.com/libgit2/pygit2/pull/889>`_ - Now it's possible to set SSL certificate locations `#876 <https://github.com/libgit2/pygit2/issues/876>`_ `#879 <https://github.com/libgit2/pygit2/pull/879>`_ `#884 <https://github.com/libgit2/pygit2/pull/884>`_ `#886 <https://github.com/libgit2/pygit2/pull/886>`_ - Test and documentation improvements `#873 <https://github.com/libgit2/pygit2/pull/873>`_ `#887 <https://github.com/libgit2/pygit2/pull/887>`_ Breaking changes: - Now ``worktree.path`` returns the path to the worktree directory, not to the `.git` file within `#803 <https://github.com/libgit2/pygit2/issues/803>`_ - Remove undocumented ``worktree.git_path`` `#803 <https://github.com/libgit2/pygit2/issues/803>`_ 0.27.4 (2019-01-19) ------------------------- - New ``pygit2.LIBGIT2_VER`` tuple `#845 <https://github.com/libgit2/pygit2/issues/845>`_ `#848 <https://github.com/libgit2/pygit2/pull/848>`_ - New objects now support (in)equality comparison and hash `#852 <https://github.com/libgit2/pygit2/issues/852>`_ `#853 <https://github.com/libgit2/pygit2/pull/853>`_ - New references now support (in)equality comparison `#860 <https://github.com/libgit2/pygit2/issues/860>`_ `#862 <https://github.com/libgit2/pygit2/pull/862>`_ - New ``paths`` optional argument in ``Repository.checkout()`` `#858 <https://github.com/libgit2/pygit2/issues/858>`_ `#859 <https://github.com/libgit2/pygit2/pull/859>`_ - Fix speed and windows package regression `#849 <https://github.com/libgit2/pygit2/issues/849>`_ `#857 <https://github.com/libgit2/pygit2/issues/857>`_ `#851 <https://github.com/libgit2/pygit2/pull/851>`_ - Fix deprecation warning `#850 <https://github.com/libgit2/pygit2/pull/850>`_ - Documentation fixes `#855 <https://github.com/libgit2/pygit2/pull/855>`_ - Add Python classifiers to setup.py `#861 <https://github.com/libgit2/pygit2/pull/861>`_ - Speeding up tests in Travis `#854 <https://github.com/libgit2/pygit2/pull/854>`_ Breaking changes: - Remove deprecated `Reference.get_object()`, use `Reference.peel()` instead 0.27.3 (2018-12-15) ------------------------- - Move to pytest, drop support for Python 3.3 and cffi 0.x `#824 <https://github.com/libgit2/pygit2/issues/824>`_ `#826 <https://github.com/libgit2/pygit2/pull/826>`_ `#833 <https://github.com/libgit2/pygit2/pull/833>`_ `#834 <https://github.com/libgit2/pygit2/pull/834>`_ - New support comparing signatures for (in)equality - New ``Submodule.head_id`` `#817 <https://github.com/libgit2/pygit2/pull/817>`_ - New ``Remote.prune(...)`` `#825 <https://github.com/libgit2/pygit2/pull/825>`_ - New ``pygit2.reference_is_valid_name(...)`` `#827 <https://github.com/libgit2/pygit2/pull/827>`_ - New ``AlreadyExistsError`` and ``InvalidSpecError`` `#828 <https://github.com/libgit2/pygit2/issues/828>`_ `#829 <https://github.com/libgit2/pygit2/pull/829>`_ - New ``Reference.raw_name``, ``Reference.raw_shorthand``, ``Tag.raw_name``, ``Tag.raw_message`` and ``DiffFile.raw_path`` `#840 <https://github.com/libgit2/pygit2/pull/840>`_ - Fix decode error in commit messages and signatures `#839 <https://github.com/libgit2/pygit2/issues/839>`_ - Fix, raise error in ``Repository.descendant_of(...)`` if commit doesn't exist `#822 <https://github.com/libgit2/pygit2/issues/822>`_ `#842 <https://github.com/libgit2/pygit2/pull/842>`_ - Documentation fixes `#821 <https://github.com/libgit2/pygit2/pull/821>`_ Breaking changes: - Remove undocumented ``Tag._message``, replaced by ``Tag.raw_message``
This PR updates [pygit2](https://pypi.org/project/pygit2) from **0.27.4** to **0.28.0**. <details> <summary>Changelog</summary> ### 0.28.0 ``` ------------------------- - Upgrade to libgit2 0.28 `878 <https://github.com/libgit2/pygit2/issues/878>`_ - Add binary wheels for Linux `793 <https://github.com/libgit2/pygit2/issues/793>`_ `869 <https://github.com/libgit2/pygit2/pull/869>`_ `874 <https://github.com/libgit2/pygit2/pull/874>`_ `875 <https://github.com/libgit2/pygit2/pull/875>`_ `883 <https://github.com/libgit2/pygit2/pull/883>`_ - New ``pygit2.Mailmap``, see documentation `804 <https://github.com/libgit2/pygit2/pull/804>`_ - New ``Repository.apply(...)`` wraps ``git_apply(..)`` `841 <https://github.com/libgit2/pygit2/issues/841>`_ `843 <https://github.com/libgit2/pygit2/pull/843>`_ - Now ``Repository.merge_analysis(...)`` accepts an optional reference parameter `888 <https://github.com/libgit2/pygit2/pull/888>`_ `891 <https://github.com/libgit2/pygit2/pull/891>`_ - Now ``Repository.add_worktree(...)`` accepts an optional reference parameter `814 <https://github.com/libgit2/pygit2/issues/814>`_ `889 <https://github.com/libgit2/pygit2/pull/889>`_ - Now it's possible to set SSL certificate locations `876 <https://github.com/libgit2/pygit2/issues/876>`_ `879 <https://github.com/libgit2/pygit2/pull/879>`_ `884 <https://github.com/libgit2/pygit2/pull/884>`_ `886 <https://github.com/libgit2/pygit2/pull/886>`_ - Test and documentation improvements `873 <https://github.com/libgit2/pygit2/pull/873>`_ `887 <https://github.com/libgit2/pygit2/pull/887>`_ Breaking changes: - Now ``worktree.path`` returns the path to the worktree directory, not to the `.git` file within `803 <https://github.com/libgit2/pygit2/issues/803>`_ - Remove undocumented ``worktree.git_path`` `803 <https://github.com/libgit2/pygit2/issues/803>`_ ``` </details> <details> <summary>Links</summary> - PyPI: https://pypi.org/project/pygit2 - Changelog: https://pyup.io/changelogs/pygit2/ - Repo: http://github.com/libgit2/pygit2 </details>
Example if you're using certifi: import certifi
import pygit2
pygit2.settings.ssl_cert_file = certifi.where() |
Closes #876
Adds support for the following
Which is the equivalent of the following in C
Also adds support for directly loading the settings from the
ssl
module like followsAll the new properties that were added to
pygit2.settings.Settings
are write only, since it is write only inlibgit2
.In addition,
pygit2
also attempts sets_ssl_cert_locations
based on thessl
module on import. This probably won't work on Windows until the wheels are changed to support this in thelibgit2
being shipped with it.