--ssl-keyfile and --ssl-certfile options to "datasette serve"

Closes #1221
This commit is contained in:
Simon Willison 2021-02-11 16:52:16 -08:00 committed by GitHub
commit eda652cf6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 2 deletions

View file

@ -408,6 +408,14 @@ def uninstall(packages, yes):
is_flag=True,
help="Create database files if they do not exist",
)
@click.option(
"--ssl-keyfile",
help="SSL key file",
)
@click.option(
"--ssl-certfile",
help="SSL certificate file",
)
def serve(
files,
immutable,
@ -432,6 +440,8 @@ def serve(
pdb,
open_browser,
create,
ssl_keyfile,
ssl_certfile,
return_instance=False,
):
"""Serve up specified SQLite database files with a web UI"""
@ -546,9 +556,14 @@ def serve(
)
url = f"http://{host}:{port}{path}"
webbrowser.open(url)
uvicorn.run(
ds.app(), host=host, port=port, log_level="info", lifespan="on", workers=1
uvicorn_kwargs = dict(
host=host, port=port, log_level="info", lifespan="on", workers=1
)
if ssl_keyfile:
uvicorn_kwargs["ssl_keyfile"] = ssl_keyfile
if ssl_certfile:
uvicorn_kwargs["ssl_certfile"] = ssl_certfile
uvicorn.run(ds.app(), **uvicorn_kwargs)
async def check_databases(ds):

View file

@ -41,4 +41,6 @@ Options:
--pdb Launch debugger on any errors
-o, --open Open Datasette in your web browser
--create Create database files if they do not exist
--ssl-keyfile TEXT SSL key file
--ssl-certfile TEXT SSL certificate file
--help Show this message and exit.

View file

@ -73,6 +73,7 @@ setup(
"beautifulsoup4>=4.8.1,<4.10.0",
"black==20.8b1",
"pytest-timeout>=1.4.2,<1.5",
"trustme>=0.7,<0.8",
],
},
tests_require=["datasette[test]"],

View file

@ -2,6 +2,11 @@ import os
import pathlib
import pytest
import re
import subprocess
import tempfile
import time
import trustme
try:
import pysqlite3 as sqlite3
@ -91,3 +96,58 @@ def check_permission_actions_are_documented():
pm.add_hookcall_monitoring(
before=before, after=lambda outcome, hook_name, hook_impls, kwargs: None
)
@pytest.fixture(scope="session")
def ds_localhost_http_server():
ds_proc = subprocess.Popen(
["datasette", "--memory", "-p", "8041"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
# Avoid FileNotFoundError: [Errno 2] No such file or directory:
cwd=tempfile.gettempdir(),
)
# Give the server time to start
time.sleep(1.5)
# Check it started successfully
assert not ds_proc.poll(), ds_proc.stdout.read().decode("utf-8")
yield ds_proc
# Shut it down at the end of the pytest session
ds_proc.terminate()
@pytest.fixture(scope="session")
def ds_localhost_https_server(tmp_path_factory):
cert_directory = tmp_path_factory.mktemp("certs")
ca = trustme.CA()
server_cert = ca.issue_cert("localhost")
keyfile = str(cert_directory / "server.key")
certfile = str(cert_directory / "server.pem")
client_cert = str(cert_directory / "client.pem")
server_cert.private_key_pem.write_to_path(path=keyfile)
for blob in server_cert.cert_chain_pems:
blob.write_to_path(path=certfile, append=True)
ca.cert_pem.write_to_path(path=client_cert)
ds_proc = subprocess.Popen(
[
"datasette",
"--memory",
"-p",
"8042",
"--ssl-keyfile",
keyfile,
"--ssl-certfile",
certfile,
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=tempfile.gettempdir(),
)
# Give the server time to start
time.sleep(1.5)
# Check it started successfully
assert not ds_proc.poll(), ds_proc.stdout.read().decode("utf-8")
yield ds_proc, client_cert
# Shut it down at the end of the pytest session
ds_proc.terminate()

View file

@ -149,6 +149,8 @@ def test_metadata_yaml():
pdb=False,
open_browser=False,
create=False,
ssl_keyfile=None,
ssl_certfile=None,
return_instance=True,
)
client = _TestClient(ds)