diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/buildless-fetches.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/buildless-fetches.buildless.expected similarity index 100% rename from java/ql/integration-tests/java/buildless-inherit-trust-store/buildless-fetches.expected rename to java/ql/integration-tests/java/buildless-inherit-trust-store/buildless-fetches.buildless.expected diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.autobuild.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.autobuild.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.buildless.expected similarity index 100% rename from java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.expected rename to java/ql/integration-tests/java/buildless-inherit-trust-store/diagnostics.buildless.expected diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.autobuild.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.autobuild.expected new file mode 100644 index 000000000000..2fcf4c22e977 --- /dev/null +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.autobuild.expected @@ -0,0 +1,4 @@ +diagnostics +| file://:0:0:0:0 | Appending source destination directory target/generated-sources/annotations to sourcepath | +#select +| DepClass | diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.expected b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.buildless.expected similarity index 100% rename from java/ql/integration-tests/java/buildless-inherit-trust-store/test.expected rename to java/ql/integration-tests/java/buildless-inherit-trust-store/test.buildless.expected diff --git a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py index 93a527620e1e..afd28d9f9bae 100644 --- a/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py +++ b/java/ql/integration-tests/java/buildless-inherit-trust-store/test.py @@ -1,21 +1,45 @@ +""" +Integration tests for truststore inheritance and merging. + +Tests that CodeQL can connect to HTTPS servers with custom CA certificates: +1. test_buildless: Buildless mode inherits truststore from MAVEN_OPTS +2. test_autobuild_merge_trust_store: Autobuild merges system truststore with + CODEQL_PROXY_CA_CERTIFICATE (fixes github/codeql-team#4482) +""" import subprocess import os +import pytest import runs_on +from contextlib import contextmanager -def test(codeql, java, cwd): - # This serves the "repo" directory on https://locahost:4443 +@contextmanager +def _https_server(cwd): + """Start an HTTPS server serving the repo/ directory on https://localhost:4443.""" command = ["python3", "../server.py"] if runs_on.github_actions and runs_on.posix: # On GitHub Actions, we saw the server timing out while running in parallel with other tests # we work around that by running it with higher permissions command = ["sudo"] + command repo_server_process = subprocess.Popen(command, cwd="repo") - certspath = cwd / "jdk8_shipped_cacerts_plus_cert_pem" - # If we override MAVEN_OPTS, we'll break cross-test maven isolation, so we need to append to it instead - maven_opts = os.environ["MAVEN_OPTS"] + f" -Djavax.net.ssl.trustStore={certspath}" - try: + yield + finally: + repo_server_process.kill() + + +@pytest.mark.ql_test(expected=".buildless.expected") +def test_buildless(codeql, java, cwd, check_diagnostics, check_buildless_fetches): + """Test that buildless mode inherits truststore from MAVEN_OPTS.""" + # Use buildless-specific expected file suffixes + check_diagnostics.expected_suffix = ".buildless.expected" + check_buildless_fetches.expected_suffix = ".buildless.expected" + + with _https_server(cwd): + certspath = cwd / "jdk8_shipped_cacerts_plus_cert_pem" + # If we override MAVEN_OPTS, we'll break cross-test maven isolation, so we need to append to it instead + maven_opts = os.environ["MAVEN_OPTS"] + f" -Djavax.net.ssl.trustStore={certspath}" + codeql.database.create( extractor_option="buildless=true", _env={ @@ -23,5 +47,39 @@ def test(codeql, java, cwd): "CODEQL_JAVA_EXTRACTOR_TRUST_STORE_PATH": str(certspath), }, ) - finally: - repo_server_process.kill() + + +@pytest.mark.ql_test(expected=".autobuild.expected") +def test_autobuild_merge_trust_store(codeql, java, cwd, check_diagnostics): + """ + Test that autobuild merges system truststore with CODEQL_PROXY_CA_CERTIFICATE. + + This tests the fix for a bug where autobuild was overriding JAVA_TOOL_OPTIONS + truststore with a new one containing only the proxy CA, causing PKIX failures + when connecting to internal HTTPS servers. + """ + # Use autobuild-specific expected file suffix + check_diagnostics.expected_suffix = ".autobuild.expected" + + with _https_server(cwd): + certspath = cwd / "jdk8_shipped_cacerts_plus_cert_pem" + + # Read the certificate to use as CODEQL_PROXY_CA_CERTIFICATE + with open(cwd / "cert.pem", "r") as f: + proxy_ca_cert = f.read() + + # Set JAVA_TOOL_OPTIONS to use our custom truststore + # This is the key setting that was being overridden before the fix + java_tool_options = f"-Djavax.net.ssl.trustStore={certspath}" + + # Run autobuild with the truststore configured + # Before the fix: autobuild would create a new truststore with ONLY the proxy CA, + # losing the custom CA from JAVA_TOOL_OPTIONS, causing PKIX failures + # After the fix: autobuild merges the system truststore + proxy CA + codeql.database.create( + build_mode="autobuild", + _env={ + "JAVA_TOOL_OPTIONS": java_tool_options, + "CODEQL_PROXY_CA_CERTIFICATE": proxy_ca_cert, + }, + )