fetchedMavenDeps: support proxy and custom cacerts (#420608)

This commit is contained in:
Philip Taron 2025-06-30 17:26:00 -07:00 committed by GitHub
commit 169776212b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 115 additions and 6 deletions

View File

@ -193,8 +193,8 @@ rec {
}:
fetcher:
let
inherit (lib.attrsets) genAttrs intersectAttrs removeAttrs;
inherit (lib.trivial) const functionArgs setFunctionArgs;
inherit (lib.attrsets) intersectAttrs removeAttrs;
inherit (lib.trivial) functionArgs setFunctionArgs;
inherit (commonH hashTypes) hashSet;
fArgs = functionArgs fetcher;

View File

@ -3,6 +3,7 @@
stdenv,
jdk,
maven,
writers,
}:
{
@ -28,6 +29,9 @@
let
mvnSkipTests = lib.optionalString (!doCheck) "-DskipTests";
writeProxySettings = writers.writePython3 "write-proxy-settings" { } ./maven-proxy.py;
fetchedMavenDeps = stdenv.mkDerivation (
{
name = "${pname}-${version}-maven-deps";
@ -39,17 +43,36 @@ let
JAVA_HOME = mvnJdk;
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
buildPhase =
''
runHook preBuild
MAVEN_EXTRA_ARGS=""
# handle proxy
if [[ -n "''${HTTP_PROXY-}" ]] || [[ -n "''${HTTPS_PROXY-}" ]] || [[ -n "''${NO_PROXY-}" ]];then
mvnSettingsFile="$(mktemp -d)/settings.xml"
${writeProxySettings} $mvnSettingsFile
MAVEN_EXTRA_ARGS="-s=$mvnSettingsFile"
fi
# handle cacert by populating a trust store on the fly
if [[ -n "''${NIX_SSL_CERT_FILE-}" ]] && [[ "''${NIX_SSL_CERT_FILE-}" != "/no-cert-file.crt" ]];then
keyStoreFile="$(mktemp -d)/keystore"
keyStorePwd="$(head -c10 /dev/random | base32)"
echo y | ${jdk}/bin/keytool -importcert -file "$NIX_SSL_CERT_FILE" -alias alias -keystore "$keyStoreFile" -storepass "$keyStorePwd"
MAVEN_EXTRA_ARGS="$MAVEN_EXTRA_ARGS -Djavax.net.ssl.trustStore=$keyStoreFile -Djavax.net.ssl.trustStorePassword=$keyStorePwd"
fi
''
+ lib.optionalString buildOffline ''
mvn de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=$out/.m2 ${mvnDepsParameters}
mvn $MAVEN_EXTRA_ARGS de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=$out/.m2 ${mvnDepsParameters}
for artifactId in ${builtins.toString manualMvnArtifacts}
do
echo "downloading manual $artifactId"
mvn dependency:get -Dartifact="$artifactId" -Dmaven.repo.local=$out/.m2
mvn $MAVEN_EXTRA_ARGS dependency:get -Dartifact="$artifactId" -Dmaven.repo.local=$out/.m2
done
for artifactId in ${builtins.toString manualMvnSources}
@ -57,11 +80,11 @@ let
group=$(echo $artifactId | cut -d':' -f1)
artifact=$(echo $artifactId | cut -d':' -f2)
echo "downloading manual sources $artifactId"
mvn dependency:sources -DincludeGroupIds="$group" -DincludeArtifactIds="$artifact" -Dmaven.repo.local=$out/.m2
mvn $MAVEN_EXTRA_ARGS dependency:sources -DincludeGroupIds="$group" -DincludeArtifactIds="$artifact" -Dmaven.repo.local=$out/.m2
done
''
+ lib.optionalString (!buildOffline) ''
mvn package -Dmaven.repo.local=$out/.m2 ${mvnSkipTests} ${mvnParameters}
mvn $MAVEN_EXTRA_ARGS package -Dmaven.repo.local=$out/.m2 ${mvnSkipTests} ${mvnParameters}
''
+ ''
runHook postBuild

View File

@ -0,0 +1,86 @@
"""
Maven doesn't honor HTTP[S]_PROXY and NO_PROXY env vars out of the box.
Instead, it expects the user to configure a settings.xml file.
We however impurely pass only these env vars in FODs.
This creates the XML file on demand, if one or more env vars is set.
"""
import os
import sys
from urllib.parse import urlparse
def parse_proxy_url(url):
if url is None:
return None
parsed = urlparse(url)
if parsed.hostname is None:
print(f"Failed to parse proxy URL {url}, ignoring", file=sys.stderr)
return None
return {
'protocol': parsed.scheme or 'http',
'host': parsed.hostname,
'port': parsed.port or (443 if parsed.scheme == 'https' else 80),
'username': parsed.username,
'password': parsed.password
}
def format_proxy_block(proxy, id_suffix, non_proxy_hosts):
auth = ""
if proxy.get("username"):
auth += f" <username>{proxy['username']}</username>\n"
if proxy.get("password"):
auth += f" <password>{proxy['password']}</password>\n"
np_hosts = ""
if non_proxy_hosts:
np_hosts = f" <nonProxyHosts>{non_proxy_hosts}</nonProxyHosts>\n"
return f""" <proxy>
<id>{id_suffix}-proxy</id>
<active>true</active>
<protocol>{proxy['protocol']}</protocol>
<host>{proxy['host']}</host>
<port>{proxy['port']}</port>
{auth}{np_hosts} </proxy>"""
def main(output_path):
http_proxy = parse_proxy_url(os.environ.get("HTTP_PROXY"))
https_proxy = parse_proxy_url(os.environ.get("HTTPS_PROXY"))
non_proxy_hosts = os.environ.get("NO_PROXY", "").replace(",", "|")
proxy_blocks = []
if http_proxy:
proxy_blocks.append(
format_proxy_block(http_proxy, "http", non_proxy_hosts)
)
if https_proxy and https_proxy != http_proxy:
proxy_blocks.append(
format_proxy_block(https_proxy, "https", non_proxy_hosts)
)
settings_xml = f"""<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<proxies>
{'\n'.join(proxy_blocks)}
</proxies>
</settings>
"""
with open(output_path, "w") as f:
f.write(settings_xml)
print(f"Generated Maven settings.xml at {output_path}")
if __name__ == "__main__":
output_file = sys.argv[1] if len(sys.argv) > 1 else "settings.xml"
main(output_file)