Summary
Java/Kotlin autobuild fails with HTTP 401 Unauthorized on every artifact when resolving from a maven_repository private registry (AWS CodeArtifact). The bundled setup-proxy.gradle init script does not propagate proxy credentials to Gradle, and interacts poorly with the current Gradle best-practice RepositoriesMode.FAIL_ON_PROJECT_REPOS. There is no configuration of settings.gradle.kts that allows a default-setup scan to succeed against CodeArtifact today.
Environment
| Item |
Value |
| CodeQL Action |
v4 (resolved 4.35.2) |
| CodeQL bundle |
codeql-bundle-v2.25.2 |
| Runner |
ubuntu-latest (GitHub-hosted), Linux 6.11.0-1018-azure x86_64 |
| JDK |
Temurin 25 |
| Gradle |
9.4.1 (./gradlew --no-daemon) |
| Registry type |
maven_repository |
| Registry URL |
https://<CA_DOMAIN>-<AWS_ACCOUNT_ID>.d.codeartifact.<AWS_REGION>.amazonaws.com/maven/<CA_REPO>/ |
Failing run URLs and full autobuild logs available privately on request.
Reproduction
- Kotlin/Gradle Spring Boot project whose
settings.gradle.kts declares an AWS CodeArtifact maven {} repo under dependencyResolutionManagement.repositories with repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS).
- Enable CodeQL default setup for Java/Kotlin on the repo.
- Configure the CodeArtifact repo under Settings → Code security → Code scanning → Protected registries as
maven_repository with aws:role-to-assume + aws:region.
- Trigger a CodeQL scan.
Expected behavior
CodeQL autobuild resolves all Maven artifacts (transitive Kotlin stdlib, Spring Boot BOMs, and internal artifacts) through the configured private registry and completes compilation so the database can be built.
Actual behavior
The proxy starts and loads credentials (visible in logs):
Credentials loaded for the following registries:
Type: maven_repository; Url: https://<CA_DOMAIN>-<AWS_ACCOUNT_ID>.d.codeartifact.<AWS_REGION>.amazonaws.com/maven/<CA_REPO>/;
AWS Region: <AWS_REGION>; AWS Account: <AWS_ACCOUNT_ID>; AWS Role: <ROLE_NAME>;
AWS Domain: <CA_DOMAIN>; AWS Domain Owner: <AWS_ACCOUNT_ID>;
…then immediately fails its own health check:
Connection test to https://<CA_DOMAIN>-<AWS_ACCOUNT_ID>.d.codeartifact.<AWS_REGION>.amazonaws.com/maven/<CA_REPO>/ failed. (404)
(The HEAD against /maven/<repo>/ legitimately returns 404 — CodeArtifact does not serve directory listings.)
Autobuild then runs:
./gradlew --no-daemon \
-Djavax.net.ssl.trustStore=<tmp>/truststore*.p12 \
-Djavax.net.ssl.trustStoreType=pkcs12 -Djavax.net.ssl.trustStorePassword=codeql \
-Dhttp.proxyHost=127.0.0.1 -Dhttps.proxyHost=127.0.0.1 \
-Dhttp.proxyPort=49152 -Dhttps.proxyPort=49152 \
--init-script /opt/hostedtoolcache/CodeQL/2.25.2/x64/codeql/java/tools/setup-proxy.gradle \
-S -Dorg.gradle.dependency.verification=off -Dorg.gradle.warning.mode=none \
--init-script /tmp/semmleTempDir.../init.gradle \
-Dorg.gradle.java.home=/usr/lib/jvm/temurin-25-jdk-amd64 \
testClasses
Note: http(s).proxyHost / proxyPort are set on the CLI, but proxyUser / proxyPassword are not.
Every artifact HEAD then 401s, e.g.:
Could not HEAD 'https://<CA_DOMAIN>-<AWS_ACCOUNT_ID>.d.codeartifact.<AWS_REGION>.amazonaws.com/maven/<CA_REPO>/org/jetbrains/kotlin/kotlin-stdlib/2.3.10/kotlin-stdlib-2.3.10.pom'.
Received status code 401 from server: Unauthorized
Root cause
Contents of /opt/hostedtoolcache/CodeQL/2.25.2/x64/codeql/java/tools/setup-proxy.gradle:
initscript {
String proxyHost = System.getenv("CODEQL_PROXY_HOST")
String proxyPort = System.getenv("CODEQL_PROXY_PORT")
String proxyUser = System.getenv("CODEQL_PROXY_USER")
String proxyPassword = System.getenv("CODEQL_PROXY_PASSWORD")
if (proxyHost != null && proxyPort != null) {
System.setProperty("http.proxyHost", proxyHost)
System.setProperty("http.proxyPort", proxyPort)
System.setProperty("https.proxyHost", proxyHost)
System.setProperty("https.proxyPort", proxyPort)
if (proxyUser != null && proxyPassword != null) {
System.setProperty("http.proxyUser", proxyUser)
System.setProperty("http.proxyPassword", proxyPassword)
System.setProperty("https.proxyUser", proxyUser)
System.setProperty("https.proxyPassword", proxyPassword)
}
}
}
allprojects {
repositories {
def proxyUrls = System.getenv("CODEQL_PROXY_URLS")
if (proxyUrls && !proxyUrls.isEmpty()) {
def parsedJson = new groovy.json.JsonSlurper().parseText(proxyUrls)
parsedJson.each { config ->
if (config.type == "maven_repository") {
maven { url = uri(config.url) }
}
}
}
}
}
Four stacked issues
1. CODEQL_PROXY_USER / CODEQL_PROXY_PASSWORD are never exported to autobuild.
The autobuild environment contains CODEQL_PROXY_HOST, CODEQL_PROXY_PORT, CODEQL_PROXY_URLS, CODEQL_PROXY_CA_CERTIFICATE — but not the user/password vars. The inner if never runs, http(s).proxyUser / proxyPassword sysprops are never set, Gradle sends no Proxy-Authorization header, the MITM proxy falls through unauthenticated, and CodeArtifact 401s.
2. Even if those env vars were exported, the JDK would block Basic auth over HTTPS tunneling.
Since 8u111, the JDK ships with jdk.http.auth.tunneling.disabledSchemes=Basic as the default. http(s).proxyUser + proxyPassword are silently ignored for HTTPS origins behind a proxy unless this is explicitly cleared:
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "")
The init script doesn't do this.
3. No credentials {} block on the init-script-added repo.
Because authentication relies entirely on the (broken) proxy, there is no Gradle-level fallback. A credentials { username = env.CODEQL_PROXY_USER; password = env.CODEQL_PROXY_PASSWORD } on the maven {} block would sidestep issue #2 entirely by authenticating at the HTTP layer against the proxy origin 127.0.0.1:49152 rather than as a proxy auth header.
4. The repo is injected at project level, which conflicts with FAIL_ON_PROJECT_REPOS.
allprojects { repositories { ... } } is a project-level declaration. With RepositoriesMode.FAIL_ON_PROJECT_REPOS (Gradle's recommended mode for new projects), the build fails at configuration time:
Build was configured to prefer settings repositories over project repositories
but repository 'maven' was added by initialization script
'/opt/hostedtoolcache/CodeQL/2.25.2/x64/codeql/java/tools/setup-proxy.gradle'
PREFER_SETTINGS silently drops the proxy repo → direct auth with no token → 401.
PREFER_PROJECT drops the user's settings-level mavenCentral(), additional public registries, and CodeArtifact declarations → Gradle only sees the init script's single CodeArtifact URL → 401 on everything including Kotlin stdlib and Spring Boot BOMs.
What was ruled out
- IAM/OIDC trust — verified working in a separate reusable workflow that exchanges OIDC for a CodeArtifact token. Same role, same
sub claim.
- Registry UI configuration — CodeQL logs confirm the registry is loaded with the correct domain/owner/region/role.
settings.gradle.kts — tested all three RepositoriesMode values, all fail (different modes).
- Gradle version — 9.4.1 (current stable); the failure is in the init script, not Gradle.
- TLS / truststore — truststore written and passed via
-Djavax.net.ssl.trustStore=.... The 401 is HTTP-layer auth, not TLS.
- Direct access — a separate
./gradlew build workflow using OIDC → aws codeartifact get-authorization-token → AWS_CODEARTIFACT_AUTH_TOKEN works flawlessly on the same runner.
Proposed fixes
In order of minimal-change:
-
Export CODEQL_PROXY_USER and CODEQL_PROXY_PASSWORD to the autobuild step, and set jdk.http.auth.tunneling.disabledSchemes="" in setup-proxy.gradle. Minimal change.
-
Attach credentials { username = ...; password = ... } to the maven {} block added in allprojects { repositories { ... } }. Bypasses the JDK Basic-auth-over-HTTPS-tunneling default because Gradle sends the credentials at HTTP layer against the proxy origin rather than as a proxy auth header.
-
Inject the repo via a settings-init script (or document a supported opt-in) so it lives in dependencyResolutionManagement.repositories and coexists with FAIL_ON_PROJECT_REPOS. The current project-level injection is incompatible with the Gradle best-practice repository mode.
-
Fix the proxy startup health check so it doesn't HEAD /maven/<repo>/ against CodeArtifact (which legitimately 404s). Use a known artifact path or skip health checks for *.codeartifact.*.amazonaws.com hosts.
Happy to test a prerelease bundle or provide a minimal reproduction repo privately.
Summary
Java/Kotlin autobuild fails with HTTP 401 Unauthorized on every artifact when resolving from a
maven_repositoryprivate registry (AWS CodeArtifact). The bundledsetup-proxy.gradleinit script does not propagate proxy credentials to Gradle, and interacts poorly with the current Gradle best-practiceRepositoriesMode.FAIL_ON_PROJECT_REPOS. There is no configuration ofsettings.gradle.ktsthat allows a default-setup scan to succeed against CodeArtifact today.Environment
v4(resolved4.35.2)codeql-bundle-v2.25.2ubuntu-latest(GitHub-hosted),Linux 6.11.0-1018-azure x86_64./gradlew --no-daemon)maven_repositoryhttps://<CA_DOMAIN>-<AWS_ACCOUNT_ID>.d.codeartifact.<AWS_REGION>.amazonaws.com/maven/<CA_REPO>/Failing run URLs and full autobuild logs available privately on request.
Reproduction
settings.gradle.ktsdeclares an AWS CodeArtifactmaven {}repo underdependencyResolutionManagement.repositorieswithrepositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS).maven_repositorywithaws:role-to-assume+aws:region.Expected behavior
CodeQL autobuild resolves all Maven artifacts (transitive Kotlin stdlib, Spring Boot BOMs, and internal artifacts) through the configured private registry and completes compilation so the database can be built.
Actual behavior
The proxy starts and loads credentials (visible in logs):
…then immediately fails its own health check:
(The HEAD against
/maven/<repo>/legitimately returns 404 — CodeArtifact does not serve directory listings.)Autobuild then runs:
Note:
http(s).proxyHost/proxyPortare set on the CLI, butproxyUser/proxyPasswordare not.Every artifact HEAD then 401s, e.g.:
Root cause
Contents of
/opt/hostedtoolcache/CodeQL/2.25.2/x64/codeql/java/tools/setup-proxy.gradle:initscript { String proxyHost = System.getenv("CODEQL_PROXY_HOST") String proxyPort = System.getenv("CODEQL_PROXY_PORT") String proxyUser = System.getenv("CODEQL_PROXY_USER") String proxyPassword = System.getenv("CODEQL_PROXY_PASSWORD") if (proxyHost != null && proxyPort != null) { System.setProperty("http.proxyHost", proxyHost) System.setProperty("http.proxyPort", proxyPort) System.setProperty("https.proxyHost", proxyHost) System.setProperty("https.proxyPort", proxyPort) if (proxyUser != null && proxyPassword != null) { System.setProperty("http.proxyUser", proxyUser) System.setProperty("http.proxyPassword", proxyPassword) System.setProperty("https.proxyUser", proxyUser) System.setProperty("https.proxyPassword", proxyPassword) } } } allprojects { repositories { def proxyUrls = System.getenv("CODEQL_PROXY_URLS") if (proxyUrls && !proxyUrls.isEmpty()) { def parsedJson = new groovy.json.JsonSlurper().parseText(proxyUrls) parsedJson.each { config -> if (config.type == "maven_repository") { maven { url = uri(config.url) } } } } } }Four stacked issues
1.
CODEQL_PROXY_USER/CODEQL_PROXY_PASSWORDare never exported to autobuild.The autobuild environment contains
CODEQL_PROXY_HOST,CODEQL_PROXY_PORT,CODEQL_PROXY_URLS,CODEQL_PROXY_CA_CERTIFICATE— but not the user/password vars. The innerifnever runs,http(s).proxyUser/proxyPasswordsysprops are never set, Gradle sends noProxy-Authorizationheader, the MITM proxy falls through unauthenticated, and CodeArtifact 401s.2. Even if those env vars were exported, the JDK would block Basic auth over HTTPS tunneling.
Since 8u111, the JDK ships with
jdk.http.auth.tunneling.disabledSchemes=Basicas the default.http(s).proxyUser+proxyPasswordare silently ignored for HTTPS origins behind a proxy unless this is explicitly cleared:The init script doesn't do this.
3. No
credentials {}block on the init-script-added repo.Because authentication relies entirely on the (broken) proxy, there is no Gradle-level fallback. A
credentials { username = env.CODEQL_PROXY_USER; password = env.CODEQL_PROXY_PASSWORD }on themaven {}block would sidestep issue #2 entirely by authenticating at the HTTP layer against the proxy origin127.0.0.1:49152rather than as a proxy auth header.4. The repo is injected at project level, which conflicts with
FAIL_ON_PROJECT_REPOS.allprojects { repositories { ... } }is a project-level declaration. WithRepositoriesMode.FAIL_ON_PROJECT_REPOS(Gradle's recommended mode for new projects), the build fails at configuration time:PREFER_SETTINGSsilently drops the proxy repo → direct auth with no token → 401.PREFER_PROJECTdrops the user's settings-levelmavenCentral(), additional public registries, and CodeArtifact declarations → Gradle only sees the init script's single CodeArtifact URL → 401 on everything including Kotlin stdlib and Spring Boot BOMs.What was ruled out
subclaim.settings.gradle.kts— tested all threeRepositoriesModevalues, all fail (different modes).-Djavax.net.ssl.trustStore=.... The 401 is HTTP-layer auth, not TLS../gradlew buildworkflow using OIDC →aws codeartifact get-authorization-token→AWS_CODEARTIFACT_AUTH_TOKENworks flawlessly on the same runner.Proposed fixes
In order of minimal-change:
Export
CODEQL_PROXY_USERandCODEQL_PROXY_PASSWORDto the autobuild step, and setjdk.http.auth.tunneling.disabledSchemes=""insetup-proxy.gradle. Minimal change.Attach
credentials { username = ...; password = ... }to themaven {}block added inallprojects { repositories { ... } }. Bypasses the JDK Basic-auth-over-HTTPS-tunneling default because Gradle sends the credentials at HTTP layer against the proxy origin rather than as a proxy auth header.Inject the repo via a settings-init script (or document a supported opt-in) so it lives in
dependencyResolutionManagement.repositoriesand coexists withFAIL_ON_PROJECT_REPOS. The current project-level injection is incompatible with the Gradle best-practice repository mode.Fix the proxy startup health check so it doesn't HEAD
/maven/<repo>/against CodeArtifact (which legitimately 404s). Use a known artifact path or skip health checks for*.codeartifact.*.amazonaws.comhosts.Happy to test a prerelease bundle or provide a minimal reproduction repo privately.