blob: 3afc89f24591cd1a32220a0330f5870bba9b0976 [file] [log] [blame]
Contributing
============
Process
-------
As an open source project, ``cryptography`` welcomes contributions of all
forms. These can include:
* Bug reports and feature requests
* Pull requests for both code and documentation
* Patch reviews
You can file bugs and submit pull requests on `GitHub`_. To discuss larger
changes you can start a conversation on `our mailing list`_.
Because cryptography is so complex, and the implications of getting it wrong so
devastating, ``cryptography`` has a strict code review policy:
* Patches must *never* be pushed directly to ``master``, all changes (even the
most trivial typo fixes!) must be submitted as a pull request.
* A committer may *never* merge their own pull request, a second party must
merge their changes. If multiple people work on a pull request, it must be
merged by someone who did not work on it.
* A patch which breaks tests, or introduces regressions by changing or removing
existing tests should not be merged. Tests must always be passing on
``master``.
* If somehow the tests get into a failing state on ``master`` (such as by a
backwards incompatible release of a dependency) no pull requests may be
merged until this is rectified.
* All merged patches must have 100% test coverage.
* New features and significant bug fixes should be documented in the
:doc:`/changelog`.
The purpose of these policies is to minimize the chances we merge a change
which jeopardizes our users' security.
If you believe you've identified a security issue in ``cryptography``, please
follow the directions on the :doc:`security page </security>`.
Code
----
When in doubt, refer to `PEP 8`_ for Python code.
Every code file must start with the boilerplate notice of the Apache License.
Additionally, every Python code file must contain
.. code-block:: python
from __future__ import absolute_import, division, print_function
API Considerations
~~~~~~~~~~~~~~~~~~
Most projects' APIs are designed with a philosophy of "make easy things easy,
and make hard things possible". One of the perils of writing cryptographic code
is that secure code looks just like insecure code, and its results are almost
always indistinguishable. As a result ``cryptography`` has, as a design
philosophy: "make it hard to do insecure things". Here are a few strategies for
API design which should be both followed, and should inspire other API choices:
If it is incorrect to ignore the result of a method, it should raise an
exception, and not return a boolean ``True``/``False`` flag. For example, a
method to verify a signature should raise ``InvalidSignature``, and not return
whether the signature was valid.
.. code-block:: python
# This is bad.
def verify(sig):
# ...
return is_valid
# Good!
def verify(sig):
# ...
if not is_valid:
raise InvalidSignature
Every recipe should include a version or algorithmic marker of some sort in its
output in order to allow transparent upgrading of the algorithms in use, as
the algorithms or parameters needed to achieve a given security margin evolve.
APIs at the :doc:`/hazmat/primitives/index` layer should always take an
explicit backend, APIs at the recipes layer should automatically use the
:func:`~cryptography.hazmat.backends.default_backend`, but optionally allow
specifying a different backend.
C bindings
~~~~~~~~~~
When binding C code with ``cffi`` we have our own style guide, it's pretty
simple.
Don't name parameters:
.. code-block:: c
// Good
long f(long);
// Bad
long f(long x);
...unless they're inside a struct:
.. code-block:: c
struct my_struct {
char *name;
int number;
...;
};
Include ``void`` if the function takes no arguments:
.. code-block:: c
// Good
long f(void);
// Bad
long f();
Wrap lines at 80 characters like so:
.. code-block:: c
// Pretend this went to 80 characters
long f(long, long,
int *)
Include a space after commas between parameters:
.. code-block:: c
// Good
long f(int, char *)
// Bad
long f(int,char *)
Values set by ``#define`` should be assigned the appropriate type. If you see
this:
.. code-block:: c
#define SOME_INTEGER_LITERAL 0x0;
#define SOME_UNSIGNED_INTEGER_LITERAL 0x0001U;
#define SOME_STRING_LITERAL "hello";
...it should be added to the bindings like so:
.. code-block:: c
static const int SOME_INTEGER_LITERAL;
static const unsigned int SOME_UNSIGNED_INTEGER_LITERAL;
static const char *const SOME_STRING_LITERAL;
Documentation
-------------
All features should be documented with prose.
Docstrings should be written like this:
.. code-block:: python
def some_function(some_arg):
"""
Does some things.
:param some_arg: Some argument.
"""
So, specifically:
* Always use three double quotes.
* Put the three double quotes on their own line.
* No blank line at the end.
* Use Sphinx parameter/attribute documentation `syntax`_.
Because of the inherent challenges in implementing correct cryptographic
systems, we want to make our documentation point people in the right directions
as much as possible. To that end:
* When documenting a generic interface, use a strong algorithm in examples.
(e.g. when showing a hashing example, don't use
:class:`~cryptography.hazmat.primitives.hashes.MD5`)
* When giving prescriptive advice, always provide references and supporting
material.
* When there is real disagreement between cryptographic experts, represent both
sides of the argument and describe the trade-offs clearly.
When documenting a new module in the ``hazmat`` package, its documentation
should begin with the "Hazardous Materials" warning:
.. code-block:: rest
.. hazmat::
When referring to a hypothetical individual (such as "a person receiving an
encrypted message") use gender neutral pronouns (they/them/their).
Development Environment
-----------------------
Working on ``cryptography`` requires the installation of a small number of
development dependencies. These are listed in ``dev-requirements.txt`` and they
can be installed in a `virtualenv`_ using `pip`_. Once you've installed the
dependencies, install ``cryptography`` in ``editable`` mode. For example:
.. code-block:: console
$ # Create a virtualenv and activate it
$ pip install --requirement dev-requirements.txt
$ pip install --editable .
You are now ready to run the tests and build the documentation.
Running Tests
~~~~~~~~~~~~~
``cryptography`` unit tests are found in the ``tests/`` directory and are
designed to be run using `pytest`_. `pytest`_ will discover the tests
automatically, so all you have to do is:
.. code-block:: console
$ py.test
...
62746 passed in 220.43 seconds
This runs the tests with the default Python interpreter.
You can also verify that the tests pass on other supported Python interpreters.
For this we use `tox`_, which will automatically create a `virtualenv`_ for
each supported Python version and run the tests. For example:
.. code-block:: console
$ tox
...
ERROR: py26: InterpreterNotFound: python2.6
py27: commands succeeded
ERROR: pypy: InterpreterNotFound: pypy
ERROR: py32: InterpreterNotFound: python3.2
py33: commands succeeded
docs: commands succeeded
pep8: commands succeeded
You may not have all the required Python versions installed, in which case you
will see one or more ``InterpreterNotFound`` errors.
Explicit Backend Selection
~~~~~~~~~~~~~~~~~~~~~~~~~~
While testing you may want to run tests against a subset of the backends that
cryptography supports. Explicit backend selection can be done via the
``--backend`` flag. This flag should be passed to ``py.test`` with a comma
delimited list of backend names. To use it with ``tox`` you must pass it as
``tox -- --backend=openssl``.
Building Documentation
~~~~~~~~~~~~~~~~~~~~~~
``cryptography`` documentation is stored in the ``docs/`` directory. It is
written in `reStructured Text`_ and rendered using `Sphinx`_.
Use `tox`_ to build the documentation. For example:
.. code-block:: console
$ tox -e docs
...
docs: commands succeeded
congratulations :)
The HTML documentation index can now be found at
``docs/_build/html/index.html``.
.. _`GitHub`: https://github.com/pyca/cryptography
.. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`PEP 8`: http://www.python.org/dev/peps/pep-0008/
.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
.. _`pytest`: https://pypi.python.org/pypi/pytest
.. _`tox`: https://pypi.python.org/pypi/tox
.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv
.. _`pip`: https://pypi.python.org/pypi/pip
.. _`sphinx`: https://pypi.python.org/pypi/sphinx
.. _`reStructured Text`: http://sphinx-doc.org/rest.html