Skip to content

Commit 10fa7d5

Browse files
Merge pull request #1593 from alexarchambault/proxy-auth
Accept authenticated proxy params via Scala CLI config file
2 parents 41eaab6 + 460d506 commit 10fa7d5

File tree

6 files changed

+139
-39
lines changed

6 files changed

+139
-39
lines changed

modules/cli/src/main/scala/scala/cli/ScalaCli.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package scala.cli
22

3-
import coursier.proxy.SetupProxy
43
import sun.misc.{Signal, SignalHandler}
54

65
import java.io.{ByteArrayOutputStream, File, PrintStream}
@@ -173,7 +172,7 @@ object ScalaCli {
173172

174173
(new BouncycastleSignerMaker).maybeInit()
175174

176-
SetupProxy.setup()
175+
coursier.Resolve.proxySetup()
177176

178177
// Getting killed by SIGPIPE quite often when on musl (in the "static" native
179178
// image), but also sometimes on glibc, or even on macOS, when we use domain

modules/integration/src/test/scala/scala/cli/integration/ConfigTests.scala

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package scala.cli.integration
22

33
import com.eed3si9n.expecty.Expecty.expect
44

5-
import java.io.File
6-
import java.util.Locale
7-
85
import scala.util.Properties
96

107
class ConfigTests extends ScalaCliSuite {
@@ -104,30 +101,9 @@ class ConfigTests extends ScalaCliSuite {
104101
if (!Properties.isWin)
105102
os.perms.set(confDir, "rwx------")
106103

107-
val extraEnv = {
108-
val (pathVarName, currentPath) = sys.env
109-
.find(_._1.toLowerCase(Locale.ROOT) == "path")
110-
.getOrElse(("PATH", ""))
111-
val binDir = root / "bin"
112-
if (Properties.isWin) {
113-
val script =
114-
s"""@echo off
115-
|"${TestUtil.cs}" %*
116-
|""".stripMargin
117-
os.write(binDir / "cs.bat", script, createFolders = true)
118-
}
119-
else {
120-
val script =
121-
s"""#!/usr/bin/env bash
122-
|exec "${TestUtil.cs}" "$$@"
123-
|""".stripMargin
124-
os.write(binDir / "cs", script, "rwxr-xr-x", createFolders = true)
125-
}
126-
Map(
127-
"SCALA_CLI_CONFIG" -> confFile.toString,
128-
pathVarName -> s"$binDir${File.pathSeparator}$currentPath"
129-
)
130-
}
104+
val extraEnv =
105+
Map("SCALA_CLI_CONFIG" -> confFile.toString) ++
106+
TestUtil.putCsInPathViaEnv(root / "bin")
131107

132108
val res = os.proc(TestUtil.cli, "config", "httpProxy.address")
133109
.call(cwd = root, env = extraEnv)

modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
721721
sudoTest()
722722
}
723723

724-
def authProxyTest(): Unit = {
724+
def authProxyTest(legacySetup: Boolean): Unit = {
725725
val okDir = os.rel / "ok"
726726
val wrongDir = os.rel / "wrong"
727727
val inputs = TestInputs(
@@ -747,10 +747,44 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
747747
s"-D$scheme.proxyProtocol=http"
748748
)
749749
}
750-
val proxyArgs = authProperties("localhost", 9083, "jack", "insecure")
751-
val wrongProxyArgs = authProperties("localhost", 9084, "wrong", "nope")
752-
val image = Constants.authProxyTestImage
750+
val proxyArgs =
751+
if (legacySetup) authProperties("localhost", 9083, "jack", "insecure")
752+
else Nil
753+
val wrongProxyArgs =
754+
if (legacySetup) authProperties("localhost", 9084, "wrong", "nope")
755+
else Nil
756+
def setupProxyConfig(
757+
cwd: os.Path,
758+
env: Map[String, String],
759+
host: String,
760+
port: Int,
761+
user: String,
762+
password: String
763+
): Unit = {
764+
os.proc(TestUtil.cli, "config", "httpProxy.address", s"http://$host:$port")
765+
.call(cwd = cwd, env = env)
766+
os.proc(TestUtil.cli, "config", "httpProxy.user", s"value:$user")
767+
.call(cwd = cwd, env = env)
768+
os.proc(TestUtil.cli, "config", "httpProxy.password", s"value:$password")
769+
.call(cwd = cwd, env = env)
770+
}
771+
val image = Constants.authProxyTestImage
753772
inputs.fromRoot { root =>
773+
val configDir = root / "configs"
774+
os.makeDir(configDir, "rwx------")
775+
val configFile = configDir / "config.json"
776+
val wrongConfigFile = configDir / "wrong-config.json"
777+
val (configEnv, wrongConfigEnv) =
778+
if (legacySetup)
779+
(Map.empty[String, String], Map.empty[String, String])
780+
else {
781+
val csEnv = TestUtil.putCsInPathViaEnv(root / "bin")
782+
val configEnv0 = Map("SCALA_CLI_CONFIG" -> configFile.toString) ++ csEnv
783+
val wrongConfigEnv0 = Map("SCALA_CLI_CONFIG" -> wrongConfigFile.toString) ++ csEnv
784+
setupProxyConfig(root, configEnv0, "localhost", 9083, "jack", "insecure")
785+
setupProxyConfig(root, wrongConfigEnv0, "localhost", 9084, "wrong", "nope")
786+
(configEnv0, wrongConfigEnv0)
787+
}
754788
DockerServer.withServer(image, root.toString, 80 -> 9083) { _ =>
755789
DockerServer.withServer(image, root.toString, 80 -> 9084) { _ =>
756790

@@ -763,7 +797,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
763797
"--cache",
764798
os.rel / "tmp-cache-ok"
765799
)
766-
.call(cwd = root / okDir)
800+
.call(cwd = root / okDir, env = configEnv)
767801
val okOutput = okRes.out.trim()
768802
expect(okOutput == "Hello proxy")
769803

@@ -776,7 +810,12 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
776810
"--cache",
777811
os.rel / "tmp-cache-wrong"
778812
)
779-
.call(cwd = root / wrongDir, mergeErrIntoOut = true, check = false)
813+
.call(
814+
cwd = root / wrongDir,
815+
env = wrongConfigEnv,
816+
mergeErrIntoOut = true,
817+
check = false
818+
)
780819
val wrongOutput = wrongRes.out.trim()
781820
expect(wrongRes.exitCode == 1)
782821
expect(wrongOutput.contains(
@@ -787,14 +826,21 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
787826
}
788827
}
789828

790-
def runAuthProxyTest: Boolean =
829+
def runAuthProxyTests: Boolean =
791830
Properties.isLinux || (Properties.isMac && !TestUtil.isCI)
792-
if (runAuthProxyTest)
831+
if (runAuthProxyTests) {
832+
test("auth proxy (legacy)") {
833+
TestUtil.retry() {
834+
authProxyTest(legacySetup = true)
835+
}
836+
}
837+
793838
test("auth proxy") {
794839
TestUtil.retry() {
795-
authProxyTest()
840+
authProxyTest(legacySetup = false)
796841
}
797842
}
843+
}
798844

799845
test("UTF-8") {
800846
val message = "Hello from TestÅÄÖåäö"

modules/integration/src/test/scala/scala/cli/integration/TestUtil.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import os.{CommandResult, Path}
44

55
import java.io.File
66
import java.net.ServerSocket
7+
import java.util.Locale
78
import java.util.concurrent.atomic.AtomicInteger
89
import java.util.concurrent.{ExecutorService, Executors, ScheduledExecutorService, ThreadFactory}
910

@@ -222,4 +223,32 @@ object TestUtil {
222223
}
223224
}
224225
}
226+
227+
def putCsInPathViaEnv(binDir: os.Path): Map[String, String] = {
228+
229+
val (pathVarName, currentPath) = sys.env
230+
.find(_._1.toLowerCase(Locale.ROOT) == "path")
231+
.getOrElse(("PATH", ""))
232+
if (Properties.isWin) {
233+
val dest = binDir / "cs.bat"
234+
if (!os.exists(dest)) {
235+
val script =
236+
s"""@echo off
237+
|"${TestUtil.cs}" %*
238+
|""".stripMargin
239+
os.write(dest, script, createFolders = true)
240+
}
241+
}
242+
else {
243+
val dest = binDir / "cs"
244+
if (!os.exists(dest)) {
245+
val script =
246+
s"""#!/usr/bin/env bash
247+
|exec "${TestUtil.cs}" "$$@"
248+
|""".stripMargin
249+
os.write(dest, script, "rwxr-xr-x", createFolders = true)
250+
}
251+
}
252+
Map(pathVarName -> s"$binDir${File.pathSeparator}$currentPath")
253+
}
225254
}

website/docs/guides/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Configuration
3-
sidebar_position: 9
3+
sidebar_position: 7
44
---
55

66
`scala-cli` can be configured in two ways:

website/docs/guides/proxies.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: Proxies
3+
sidebar_position: 8
4+
---
5+
6+
## HTTP proxies
7+
8+
### Configuration
9+
10+
If you can only download artifacts through a proxy, you need to configure it beforehand, like
11+
```text
12+
scala-cli config httpProxy.address http://proxy.company.com
13+
```
14+
15+
Replace `proxy.company.com` by the address of your proxy.
16+
17+
Change `http://` to `https://` if your proxy is accessible via HTTPS.
18+
19+
### Authentication
20+
21+
If your proxy requires authentication, set your user and password with
22+
```text
23+
scala-cli config httpProxy.user _encoded_user_
24+
scala-cli config httpProxy.password _encoded_password_
25+
```
26+
27+
Replace `_encoded_user_` and `_encoded_password_` by your actual user and password, following
28+
the [password option format](../reference/password-options.md). They should typically look like
29+
`env:ENV_VAR_NAME`, `file:/path/to/file`, or `command:command to run`.
30+
31+
## Default repositories
32+
33+
If you don't rely on proxies, but rather download artifacts through different Maven repositories,
34+
set those repositories like:
35+
```text
36+
scala-cli config repositories.default https://first-repo.company.com https://second-repo.company.com
37+
```
38+
39+
## Mirrors
40+
41+
If you're fine directly downloading artifacts from the internet, but would rather have some
42+
repositories requests go through a repository of yours, configure mirror repositories, like
43+
```text
44+
scala-cli config repositories.mirrors https://repo1.maven.org/maven2=https://repository.company.com/maven
45+
```
46+
47+
To have all requests to a Maven repository go through a repository of yours, do
48+
```text
49+
scala-cli config repositories.mirrors maven:*=https://repository.company.com/maven
50+
```

0 commit comments

Comments
 (0)