From aa81b8c9e00b9351af45d73c423f6b0655cc8837 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 10 Dec 2025 16:45:05 +0100 Subject: [PATCH 1/2] Build: set `GIT_SSH_COMMAND` to avoid host key checking for private repos Closes https://github.com/readthedocs/readthedocs-corporate/pull/2076 Closes https://github.com/readthedocs/readthedocs-corporate/issues/788 --- readthedocs/doc_builder/director.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/readthedocs/doc_builder/director.py b/readthedocs/doc_builder/director.py index d212b0e5c9f..2d202595a24 100644 --- a/readthedocs/doc_builder/director.py +++ b/readthedocs/doc_builder/director.py @@ -798,6 +798,17 @@ def get_build_env_vars(self): } ) + if settings.ALLOW_PRIVATE_REPOS: + # Set GIT_SSH_COMMAND to use ssh with options that disable host key checking + # -o StrictHostKeyChecking=no: Don't prompt for host verification + # -o UserKnownHostsFile=/dev/null: Don't save host keys + git_ssh_command = "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" + env.update( + { + "GIT_SSH_COMMAND": git_ssh_command, + } + ) + # Update environment from Project's specific environment variables, # avoiding to expose private environment variables # if the version is external (i.e. a PR build). From 21ba24c0005e1996cc2dd7638fe633b98f861e1e Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 10 Dec 2025 17:02:35 +0100 Subject: [PATCH 2/2] Add test case for this --- .../doc_builder/tests/test_director.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 readthedocs/doc_builder/tests/test_director.py diff --git a/readthedocs/doc_builder/tests/test_director.py b/readthedocs/doc_builder/tests/test_director.py new file mode 100644 index 00000000000..6228ce6c2b5 --- /dev/null +++ b/readthedocs/doc_builder/tests/test_director.py @@ -0,0 +1,52 @@ +from unittest import mock + +from django.test import TestCase, override_settings +from django_dynamic_fixture import get + +from readthedocs.builds.models import Build, Version +from readthedocs.doc_builder.director import BuildDirector +from readthedocs.projects.models import Project + + +class TestBuildDirectorEnvironmentVariables(TestCase): + """Test environment variables set by BuildDirector.""" + + def setUp(self): + self.project = get(Project, slug="test-project") + self.version = self.project.versions.get(slug="latest") + self.build = get( + Build, + project=self.project, + version=self.version, + commit="abc123", + ) + + # Required since it's a APIVersion behind the scenes + self.version.canonical_url = "https://test-project.readthedocs.io/en/latest/" + + # Create a minimal data object that BuildDirector expects + self.data = mock.Mock() + self.data.project = self.project + self.data.version = self.version + self.data.build = {"commit": "abc123"} + self.data.config = mock.Mock() + self.data.config.conda = None + + self.director = BuildDirector(self.data) + + @override_settings(ALLOW_PRIVATE_REPOS=True) + def test_git_ssh_command_set_when_private_repos_enabled(self): + """Test that GIT_SSH_COMMAND is set when ALLOW_PRIVATE_REPOS is True.""" + env_vars = self.director.get_build_env_vars() + self.assertIn("GIT_SSH_COMMAND", env_vars) + # Verify it contains the ssh command with proper options + self.assertEqual( + env_vars["GIT_SSH_COMMAND"], + "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null", + ) + + @override_settings(ALLOW_PRIVATE_REPOS=False) + def test_git_ssh_command_not_set_when_private_repos_disabled(self): + """Test that GIT_SSH_COMMAND is not set when ALLOW_PRIVATE_REPOS is False.""" + env_vars = self.director.get_build_env_vars() + self.assertNotIn("GIT_SSH_COMMAND", env_vars)