Look up the machine's certificates rather than the build machine's

A build carries the OpenSSL of the machine it was built on, and that
OpenSSL has one directory compiled into it as the only place it looks for
certificates. For an AppImage built on Ubuntu that is /usr/lib/ssl, which
Arch, Fedora and openSUSE do not have, so on any of them every HTTPS
request fails with CERTIFICATE_VERIFY_FAILED: transcription and cleanup
report it as a rejected key, and the model downloads fail too.

Ask the machine instead, from the list curl and Go use, and only when the
build's own answer turns out not to exist. The store on the machine
rather than a copy carried along, because a copy goes stale as roots are
rotated and would ignore a certificate somebody added themselves. Anybody
who has already set SSL_CERT_FILE is left alone.
This commit is contained in:
2026-08-16 15:24:33 +03:00
parent f247752bc1
commit 4cec05fa49
3 changed files with 112 additions and 2 deletions
+53
View File
@@ -14,6 +14,12 @@ Everything is written from the path Dikte is running as, which is why it is
also run again on every start rather than once: an AppImage that was moved out
of ~/Downloads leaves behind a menu entry naming a file that is no longer
there, and the run after the move is the only moment that can be noticed.
The rest of the module is the other half of the same meeting. A build carries
the libraries and the OpenSSL of the machine it was built on, and both of them
have to be reconciled with the machine it is running on before anything else
happens: what it hands to the programs it starts, and where it looks for the
certificates that say who it is talking to.
"""
import os
@@ -89,6 +95,53 @@ def restore_library_path():
return moved
# Where the distributions keep the trust store. One list rather than a guess
# per distribution, in the order curl and Go try them.
CA_FILES = (
"/etc/ssl/certs/ca-certificates.crt", # Debian, Ubuntu, Arch, Gentoo
"/etc/pki/tls/certs/ca-bundle.crt", # Fedora, RHEL
"/etc/ssl/ca-bundle.pem", # openSUSE
"/etc/ssl/cert.pem", # Alpine, and macOS
)
CA_DIRECTORIES = ("/etc/ssl/certs", "/etc/pki/tls/certs")
def use_system_certificates():
"""Point the OpenSSL in this build at the machine's trust store. What it found.
A build carries the OpenSSL of the machine it was built on, and that
OpenSSL has one directory compiled into it as the only place it will look:
/usr/lib/ssl for an AppImage built on Ubuntu, which does not exist on Arch,
Fedora or openSUSE. Every HTTPS request then fails with
CERTIFICATE_VERIFY_FAILED, which reads like a rejected API key rather than
a packaging fault, and takes the model downloads down with it.
The machine's own store rather than a copy carried along: a copy goes stale
as roots are rotated, and it would ignore a certificate somebody added
themselves, which is how a network that inspects its own traffic is made to
work. Anybody who has already said where to look is not argued with.
"""
if not packaged():
return None
if os.environ.get("SSL_CERT_FILE") or os.environ.get("SSL_CERT_DIR"):
return None
import ssl
# Both of these are None unless the path they name is really there, so this
# asks whether the build's idea of where certificates live survived the trip.
defaults = ssl.get_default_verify_paths()
if defaults.cafile or defaults.capath:
return None
for name, candidates, exists in (("SSL_CERT_FILE", CA_FILES, os.path.isfile),
("SSL_CERT_DIR", CA_DIRECTORIES, os.path.isdir)):
for candidate in candidates:
if exists(candidate):
os.environ[name] = candidate
return candidate
return None
def bundled_bin():
"""Where a build keeps the helper programs it carries, if it carries any.
+4 -2
View File
@@ -7,8 +7,9 @@ The Finder hands a double-clicked application a -psn_0_… argument naming the
process serial number, which argparse reads as a flag it has never heard of and
exits over, and no one clicking an icon would ever find out why.
The two environment lines have to run before anything starts another process,
and before is easier to be sure of here than anywhere further in.
The three environment lines have to run before anything starts a process,
opens a connection or reaches for ffmpeg, and before is easier to be sure of
here than anywhere further in.
"""
import sys
@@ -18,6 +19,7 @@ from dikte.app import main
if __name__ == "__main__":
integrate.restore_library_path()
integrate.use_system_certificates()
integrate.add_bundled_tools()
sys.argv[1:] = [arg for arg in sys.argv[1:] if not arg.startswith("-psn_")]
sys.exit(main())
+55
View File
@@ -158,6 +158,61 @@ class LibraryPath(unittest.TestCase):
self.assertFalse(integrate.restore_library_path())
class Certificates(unittest.TestCase):
"""Where a build looks for the certificates that say who it is talking to.
An AppImage built on Ubuntu carries an OpenSSL with /usr/lib/ssl compiled
into it, and Arch, Fedora and openSUSE have no such directory. Left alone
it is every HTTPS request failing at once, reported as a rejected key.
"""
def paths(self, cafile=None, capath=None):
"""ssl.get_default_verify_paths(), which reports only what really exists."""
import ssl
return mock.patch("ssl.get_default_verify_paths",
return_value=ssl.DefaultVerifyPaths(
cafile, capath, "SSL_CERT_FILE", "/usr/lib/ssl/cert.pem",
"SSL_CERT_DIR", "/usr/lib/ssl/certs"))
def test_a_store_the_build_cannot_find_is_looked_up(self):
with Frozen("/tmp/.mount_x/usr/bin/dikte"), \
mock.patch.dict(os.environ, {}, clear=True), \
self.paths(), \
mock.patch("os.path.isfile", lambda p: p == "/etc/ssl/cert.pem"):
self.assertEqual(integrate.use_system_certificates(), "/etc/ssl/cert.pem")
self.assertEqual(os.environ["SSL_CERT_FILE"], "/etc/ssl/cert.pem")
def test_a_directory_will_do_when_no_bundle_is_there(self):
with Frozen("/tmp/.mount_x/usr/bin/dikte"), \
mock.patch.dict(os.environ, {}, clear=True), \
self.paths(), \
mock.patch("os.path.isfile", return_value=False), \
mock.patch("os.path.isdir", lambda p: p == "/etc/ssl/certs"):
self.assertEqual(integrate.use_system_certificates(), "/etc/ssl/certs")
self.assertEqual(os.environ["SSL_CERT_DIR"], "/etc/ssl/certs")
def test_a_build_that_can_already_find_them_is_left_alone(self):
"""Which is the AppImage running on the distribution it was built on."""
with Frozen("/tmp/.mount_x/usr/bin/dikte"), \
mock.patch.dict(os.environ, {}, clear=True), \
self.paths(capath="/usr/lib/ssl/certs"):
self.assertIsNone(integrate.use_system_certificates())
self.assertNotIn("SSL_CERT_FILE", os.environ)
def test_somebody_who_has_said_where_is_not_argued_with(self):
"""A network that inspects its own traffic is made to work this way."""
with Frozen("/tmp/.mount_x/usr/bin/dikte"), \
mock.patch.dict(os.environ, {"SSL_CERT_FILE": "/opt/work/ca.pem"},
clear=True), \
self.paths():
self.assertIsNone(integrate.use_system_certificates())
self.assertEqual(os.environ["SSL_CERT_FILE"], "/opt/work/ca.pem")
def test_a_checkout_uses_the_python_it_was_installed_against(self):
with mock.patch.dict(os.environ, {}, clear=True):
self.assertIsNone(integrate.use_system_certificates())
class Linux(Home):
def install(self, appimage, force=False):
with Frozen("/tmp/.mount_x/usr/bin/dikte", appimage=str(appimage),