# trustme gives your test suite a certificate authority of its own

> trustme is a small Python package from the Trio project that creates a certificate authority in memory and issues test certificates signed by it, so a test suite can make real TLS connections without disabling certificate validation. It also ships a command line tool and stays deliberately out of the system trust store.

**python-trio/trustme** — #1 quality TLS certs while you wait, for the discerning tester

- Repository: https://github.com/python-trio/trustme
- Website: https://trustme.rtfd.io
- Stars: 605 · Forks: 35
- Language: Python
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/python-trio-trustme

## The problem is a test suite that has no valid certificate

The scenario the package describes is narrow and extremely common. You wrote a network client or a server, it encrypts connections with TLS, and your test suite needs to make TLS connections to itself. Then the problem arrives: your test suite probably does not have a valid TLS certificate.

The usual workarounds are both bad. You can use a self-signed certificate, which means the client side has to be told to skip validation, and every test that connects has to carry that exception. Or you can try to get a real certificate, which for a test host is slow, needs a public name, and eventually expires.

trustme is a tiny Python package that does one thing: it gives you a fake certificate authority that you can use to generate fake TLS certificates for your tests. The readme is precise about the nuance, saying that technically they are real certificates, they are just signed by your CA, which nobody trusts, and that you can trust it.

That distinction is the whole point. Because the certificates are properly signed by a CA the test can install as a trust anchor, the client side of the test keeps its validation code intact. The readme makes the argument plainly: you do not have to disable your certificate validation code in your test suite, which is good because you want to test what you run in production, and you would never disable your certificate validation code in production.

## Three calls: make a CA, issue a cert, configure a context

The programmatic API is small enough to read in one sitting, and the readme's cheat sheet is the reference.

```python
   import trustme

   # Look, you just created your certificate authority!
   ca = trustme.CA()

   # And now you issued a cert signed by this fake CA
   # https://en.wikipedia.org/wiki/Example.org
   server_cert = ca.issue_cert("test-host.example.org")
```

Then the same objects configure an SSL context, either to trust the CA or to present the certificate. The readme notes that standard library or PyOpenSSL context objects both work and that trustme is happy either way.

```python
   # You can configure SSL context objects to trust this CA:
   ca.configure_trust(ssl_context)
   # Or configure them to present the server certificate
   server_cert.configure_cert(ssl_context)
```

There is no configuration object, no registry and no global state. A CA is an object, a certificate is an object, and both know how to apply themselves to a context. That is what makes the package usable in a fixture: you create the CA once per test session, hand the same CA to every client that needs to trust it, and the certificates are issued per host name.

The subject name is passed to issue_cert, so the same CA can mint certificates for as many hosts as a test needs, which is what lets a test check that a client validates the name it expects rather than any certificate at all.

## PEM files on disk, or a temporary file for libraries that insist

Not every client in a test suite is a Python object you can hand an SSL context. Some want a path to a PEM file, and some want a file that exists only for the duration of a call.

For the first case, the certificate and key objects write themselves out, with a write_to_path method.

```python
   # Save the PEM-encoded data to a file to use in non-Python test
   # suites:
   ca.cert_pem.write_to_path("ca.pem")
   server_cert.private_key_and_cert_chain_pem.write_to_path("server.pem")
```

For the second case there is a context manager that yields a temporary path, which is what the readme suggests for libraries that insist on a file.

```python
   # Put the PEM-encoded data in a temporary file, for libraries that
   # insist on that:
   with ca.cert_pem.tempfile() as ca_temp_path:
       requests.get("https://...", verify=ca_temp_path)
```

The example there passes that path as the verify argument of a requests call, which is the common case: a test asserting against a real HTTP client rather than against your own code. The temporary file disappears when the block ends, so there is no stale CA left on a developer's machine to cause a confusing failure later.

Between the three shapes, the package covers the realistic set: in-process contexts, files on disk, and a scoped temporary path.

## The command line tool prints the paths you need

There is a second way in, and it is the one to reach for when the server and the client are not both Python, for example when a test starts gunicorn and then curls it.

Running the module generates a certificate and reports where the files landed.

```console
   $ python -m trustme
   Generated a certificate for 'localhost', '127.0.0.1', '::1'
   Configure your server to use the following files:
     cert=/tmp/server.pem
     key=/tmp/server.key
   Configure your client to use the following files:
     cert=/tmp/client.pem
```

The generated certificate covers localhost, 127.0.0.1 and ::1, which is exactly the set of names a local test server needs, and the tool prints both the server side and the client side paths. The readme's session continues by starting gunicorn with the key and certificate files and then pointing curl at the server with the client CA file as its cacert, which produces a successful TLS request with full validation.

The console entry point in the project metadata is trustme._cli:main, and the readme notes that certificates may be generated from anywhere, showing the working directory first so the /tmp paths in the output are not mysterious.

## The two things trustme refuses to do

The FAQ in the readme is short, and two of its answers define the scope of the package.

The first is that trustme will not automate installing the CA into the system trust store, and it says why: mkcert already does this well, and the project would not have anything to add. That is a real boundary, and it changes who can use the tool. Because nothing is installed system wide, a browser, a Go program or any other client outside your test process will not trust the CA. The readme's own example stays inside that boundary by passing the client certificate to curl with an explicit cacert flag.

The second is about exotic TLS configurations. The readme says it thinks trustme hits a sweet spot of ease of use and generality, that the defaults are carefully chosen to work on all major operating systems and be as fast as possible, and that it does not want to turn trustme into a second rate re-export of everything in the cryptography library. If you have more complex needs, the readme says to consider using cryptography directly, possibly starting from the trustme code.

That is an honest answer to a question people ask about any small abstraction: what happens when my case does not fit. Here the answer is that you drop down a level, and the project would rather you did that than grow.

The first FAQ entry is the one to memorise: should I use these certs for anything real? Certainly not.

## A package from the Trio project, dual licensed, with a release cadence

trustme is maintained under the python-trio organisation, with Nathaniel J. Smith listed as the author in the project metadata, and the documentation at trustme.readthedocs.io.

The licence is dual, and the readme states it plainly: MIT or Apache 2, your choice. The repository carries both LICENSE.MIT and LICENSE.APACHE2 alongside a LICENSE file, and the project metadata records the licence as MIT OR Apache-2.0, with both licences appearing in the classifier list. That is a permissive pairing with no obligations beyond attribution and notice.

The packaging is hatchling, with the version read dynamically from src/trustme/_version.py rather than hard coded in the metadata, and the project requires Python 3.10 or newer. The classifiers list CPython and PyPy, and include a beta marker for free threaded Python, which tells you the project is being tested against the newer interpreter modes rather than only the standard build. The runtime dependencies are small: cryptography at 3.1 or newer and idna at 2.0 or newer, which is what lets the package issue certificates for internationalised host names without pulling in a web framework.

The development setup is visible in the repository as well, with a noxfile.py for the test sessions, separate lint and test requirement files, documentation requirements, and a towncrier setup where pull requests drop a file into newsfragments.

On releases, the tagged versions are 1.2.1 in January 2025, 1.2.0 and 1.1.0 in October 2024, and the repository is not archived with the last push on 2026-10-06. The metadata marks the project as Production/Stable, so the version numbers are low but the project is not experimental.

## Conclusion

trustme fits a Python project whose tests need to speak TLS to themselves, or to a service under test, and which would rather keep certificate validation switched on than disable it. It is the wrong tool if you need the CA trusted by the operating system or by a browser, since it will not install anything into a trust store, and it is the wrong tool if you need exotic TLS configurations, since the project points you at the cryptography library for that. Check first that your test client can be given a CA file or an SSL context, that Python 3.10 or newer is available, and that the dual MIT and Apache 2 licence suits your distribution.

## FAQ

### How do I install trustme and create a test certificate?

Run pip install -U trustme, then create a CA with trustme.CA() and issue a certificate with ca.issue_cert("test-host.example.org"). Apply them to an SSL context with ca.configure_trust and server_cert.configure_cert.

### Why use trustme instead of a self-signed certificate?

Because the certificates are signed by a CA your test can trust, so you do not have to disable certificate validation in your test suite. The readme notes you would never disable that validation code in production, so testing with it switched off means you are not testing what you run.

### Does trustme install its CA into the system trust store?

No, and it will not. The readme says it will not automate installing the CA into the system trust store, because mkcert already does that well. Clients outside the test process need the CA file passed to them explicitly.

### What if I need an unusual TLS configuration?

The readme says the defaults target a sweet spot of ease of use and generality, work on all major operating systems and are fast, and that trustme should not become a re-export of the cryptography library. For more complex needs it points you at cryptography directly, possibly starting from the trustme code.

## Sources

- [Issues](https://github.com/python-trio/trustme/issues)
- [Project website](https://trustme.rtfd.io)
- [python-trio/trustme on GitHub](https://github.com/python-trio/trustme)
- [README](https://github.com/python-trio/trustme/blob/main/README.md)
- [Releases](https://github.com/python-trio/trustme/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/python-trio-trustme
